diff options
Diffstat (limited to 'contrib/gcc/dwarf2out.c')
-rw-r--r-- | contrib/gcc/dwarf2out.c | 10142 |
1 files changed, 0 insertions, 10142 deletions
diff --git a/contrib/gcc/dwarf2out.c b/contrib/gcc/dwarf2out.c deleted file mode 100644 index 7ce80506fdc7..000000000000 --- a/contrib/gcc/dwarf2out.c +++ /dev/null @@ -1,10142 +0,0 @@ -/* Output Dwarf2 format symbol table information from the GNU C compiler. - Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000 Free Software - Foundation, Inc. - Contributed by Gary Funck (gary@intrepid.com). - Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com). - Extensively modified by Jason Merrill (jason@cygnus.com). - -This file is part of GNU CC. - -GNU CC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU CC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -/* The first part of this file deals with the DWARF 2 frame unwind - information, which is also used by the GCC efficient exception handling - mechanism. The second part, controlled only by an #ifdef - DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging - information. */ - -#include "config.h" -#include "system.h" -#include "defaults.h" -#include "tree.h" -#include "flags.h" -#include "rtl.h" -#include "hard-reg-set.h" -#include "regs.h" -#include "insn-config.h" -#include "reload.h" -#include "output.h" -#include "expr.h" -#include "except.h" -#include "dwarf2.h" -#include "dwarf2out.h" -#include "toplev.h" -#include "dyn-string.h" - -/* We cannot use <assert.h> in GCC source, since that would include - GCC's assert.h, which may not be compatible with the host compiler. */ -#undef assert -#ifdef NDEBUG -# define assert(e) -#else -# define assert(e) do { if (! (e)) abort (); } while (0) -#endif - -/* Decide whether we want to emit frame unwind information for the current - translation unit. */ - -int -dwarf2out_do_frame () -{ - return (write_symbols == DWARF2_DEBUG -#ifdef DWARF2_FRAME_INFO - || DWARF2_FRAME_INFO -#endif -#ifdef DWARF2_UNWIND_INFO - || (flag_exceptions && ! exceptions_via_longjmp) -#endif - ); -} - -#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO) - -/* How to start an assembler comment. */ -#ifndef ASM_COMMENT_START -#define ASM_COMMENT_START ";#" -#endif - -typedef struct dw_cfi_struct *dw_cfi_ref; -typedef struct dw_fde_struct *dw_fde_ref; -typedef union dw_cfi_oprnd_struct *dw_cfi_oprnd_ref; - -/* Call frames are described using a sequence of Call Frame - Information instructions. The register number, offset - and address fields are provided as possible operands; - their use is selected by the opcode field. */ - -typedef union dw_cfi_oprnd_struct -{ - unsigned long dw_cfi_reg_num; - long int dw_cfi_offset; - char *dw_cfi_addr; -} -dw_cfi_oprnd; - -typedef struct dw_cfi_struct -{ - dw_cfi_ref dw_cfi_next; - enum dwarf_call_frame_info dw_cfi_opc; - dw_cfi_oprnd dw_cfi_oprnd1; - dw_cfi_oprnd dw_cfi_oprnd2; -} -dw_cfi_node; - -/* All call frame descriptions (FDE's) in the GCC generated DWARF - refer to a single Common Information Entry (CIE), defined at - the beginning of the .debug_frame section. This used of a single - CIE obviates the need to keep track of multiple CIE's - in the DWARF generation routines below. */ - -typedef struct dw_fde_struct -{ - char *dw_fde_begin; - char *dw_fde_current_label; - char *dw_fde_end; - dw_cfi_ref dw_fde_cfi; -} -dw_fde_node; - -/* Maximum size (in bytes) of an artificially generated label. */ -#define MAX_ARTIFICIAL_LABEL_BYTES 30 - -/* Make sure we know the sizes of the various types dwarf can describe. These - are only defaults. If the sizes are different for your target, you should - override these values by defining the appropriate symbols in your tm.h - file. */ - -#ifndef CHAR_TYPE_SIZE -#define CHAR_TYPE_SIZE BITS_PER_UNIT -#endif -#ifndef PTR_SIZE -#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT) -#endif - -/* The size in bytes of a DWARF field indicating an offset or length - relative to a debug info section, specified to be 4 bytes in the DWARF-2 - specification. The SGI/MIPS ABI defines it to be the same as PTR_SIZE. */ - -#ifndef DWARF_OFFSET_SIZE -#define DWARF_OFFSET_SIZE 4 -#endif - -#define DWARF_VERSION 2 - -/* Round SIZE up to the nearest BOUNDARY. */ -#define DWARF_ROUND(SIZE,BOUNDARY) \ - (((SIZE) + (BOUNDARY) - 1) & ~((BOUNDARY) - 1)) - -/* Offsets recorded in opcodes are a multiple of this alignment factor. */ -#ifdef STACK_GROWS_DOWNWARD -#define DWARF_CIE_DATA_ALIGNMENT (-UNITS_PER_WORD) -#else -#define DWARF_CIE_DATA_ALIGNMENT UNITS_PER_WORD -#endif - -/* A pointer to the base of a table that contains frame description - information for each routine. */ -static dw_fde_ref fde_table; - -/* Number of elements currently allocated for fde_table. */ -static unsigned fde_table_allocated; - -/* Number of elements in fde_table currently in use. */ -static unsigned fde_table_in_use; - -/* Size (in elements) of increments by which we may expand the - fde_table. */ -#define FDE_TABLE_INCREMENT 256 - -/* A list of call frame insns for the CIE. */ -static dw_cfi_ref cie_cfi_head; - -/* The number of the current function definition for which debugging - information is being generated. These numbers range from 1 up to the - maximum number of function definitions contained within the current - compilation unit. These numbers are used to create unique label id's - unique to each function definition. */ -static unsigned current_funcdef_number = 0; - -/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram - attribute that accelerates the lookup of the FDE associated - with the subprogram. This variable holds the table index of the FDE - associated with the current function (body) definition. */ -static unsigned current_funcdef_fde; - -/* Forward declarations for functions defined in this file. */ - -static char *stripattributes PROTO((char *)); -static char *dwarf_cfi_name PROTO((unsigned)); -static dw_cfi_ref new_cfi PROTO((void)); -static void add_cfi PROTO((dw_cfi_ref *, dw_cfi_ref)); -static unsigned long size_of_uleb128 PROTO((unsigned long)); -static unsigned long size_of_sleb128 PROTO((long)); -static void output_uleb128 PROTO((unsigned long)); -static void output_sleb128 PROTO((long)); -static void add_fde_cfi PROTO((char *, dw_cfi_ref)); -static void lookup_cfa_1 PROTO((dw_cfi_ref, unsigned long *, - long *)); -static void lookup_cfa PROTO((unsigned long *, long *)); -static void reg_save PROTO((char *, unsigned, unsigned, - long)); -static void initial_return_save PROTO((rtx)); -static void output_cfi PROTO((dw_cfi_ref, dw_fde_ref)); -static void output_call_frame_info PROTO((int)); -static unsigned reg_number PROTO((rtx)); -static void dwarf2out_stack_adjust PROTO((rtx)); - -/* Definitions of defaults for assembler-dependent names of various - pseudo-ops and section names. - Theses may be overridden in the tm.h file (if necessary) for a particular - assembler. */ - -#ifdef OBJECT_FORMAT_ELF -#ifndef UNALIGNED_SHORT_ASM_OP -#define UNALIGNED_SHORT_ASM_OP ".2byte" -#endif -#ifndef UNALIGNED_INT_ASM_OP -#define UNALIGNED_INT_ASM_OP ".4byte" -#endif -#ifndef UNALIGNED_DOUBLE_INT_ASM_OP -#define UNALIGNED_DOUBLE_INT_ASM_OP ".8byte" -#endif -#endif /* OBJECT_FORMAT_ELF */ - -#ifndef ASM_BYTE_OP -#define ASM_BYTE_OP ".byte" -#endif - -/* Data and reference forms for relocatable data. */ -#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4) -#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4) - -/* Pseudo-op for defining a new section. */ -#ifndef SECTION_ASM_OP -#define SECTION_ASM_OP ".section" -#endif - -/* The default format used by the ASM_OUTPUT_SECTION macro (see below) to - print the SECTION_ASM_OP and the section name. The default here works for - almost all svr4 assemblers, except for the sparc, where the section name - must be enclosed in double quotes. (See sparcv4.h). */ -#ifndef SECTION_FORMAT -#ifdef PUSHSECTION_FORMAT -#define SECTION_FORMAT PUSHSECTION_FORMAT -#else -#define SECTION_FORMAT "\t%s\t%s\n" -#endif -#endif - -#ifndef FRAME_SECTION -#define FRAME_SECTION ".debug_frame" -#endif - -#ifndef FUNC_BEGIN_LABEL -#define FUNC_BEGIN_LABEL "LFB" -#endif -#ifndef FUNC_END_LABEL -#define FUNC_END_LABEL "LFE" -#endif -#define CIE_AFTER_SIZE_LABEL "LSCIE" -#define CIE_END_LABEL "LECIE" -#define CIE_LENGTH_LABEL "LLCIE" -#define FDE_AFTER_SIZE_LABEL "LSFDE" -#define FDE_END_LABEL "LEFDE" -#define FDE_LENGTH_LABEL "LLFDE" - -/* Definitions of defaults for various types of primitive assembly language - output operations. These may be overridden from within the tm.h file, - but typically, that is unnecessary. */ - -#ifndef ASM_OUTPUT_SECTION -#define ASM_OUTPUT_SECTION(FILE, SECTION) \ - fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION) -#endif - -#ifndef ASM_OUTPUT_DWARF_DATA1 -#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \ - fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) (VALUE)) -#endif - -#ifndef ASM_OUTPUT_DWARF_DELTA1 -#define ASM_OUTPUT_DWARF_DELTA1(FILE,LABEL1,LABEL2) \ - do { fprintf ((FILE), "\t%s\t", ASM_BYTE_OP); \ - assemble_name (FILE, LABEL1); \ - fprintf (FILE, "-"); \ - assemble_name (FILE, LABEL2); \ - } while (0) -#endif - -#ifdef UNALIGNED_INT_ASM_OP - -#ifndef UNALIGNED_OFFSET_ASM_OP -#define UNALIGNED_OFFSET_ASM_OP \ - (DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP) -#endif - -#ifndef UNALIGNED_WORD_ASM_OP -#define UNALIGNED_WORD_ASM_OP \ - (PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP) -#endif - -#ifndef ASM_OUTPUT_DWARF_DELTA2 -#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \ - do { fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP); \ - assemble_name (FILE, LABEL1); \ - fprintf (FILE, "-"); \ - assemble_name (FILE, LABEL2); \ - } while (0) -#endif - -#ifndef ASM_OUTPUT_DWARF_DELTA4 -#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \ - do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ - assemble_name (FILE, LABEL1); \ - fprintf (FILE, "-"); \ - assemble_name (FILE, LABEL2); \ - } while (0) -#endif - -#ifndef ASM_OUTPUT_DWARF_DELTA -#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \ - do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \ - assemble_name (FILE, LABEL1); \ - fprintf (FILE, "-"); \ - assemble_name (FILE, LABEL2); \ - } while (0) -#endif - -#ifndef ASM_OUTPUT_DWARF_ADDR_DELTA -#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \ - do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ - assemble_name (FILE, LABEL1); \ - fprintf (FILE, "-"); \ - assemble_name (FILE, LABEL2); \ - } while (0) -#endif - -#ifndef ASM_OUTPUT_DWARF_ADDR -#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \ - do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \ - assemble_name (FILE, LABEL); \ - } while (0) -#endif - -/* ??? This macro takes an RTX in dwarfout.c and a string in dwarf2out.c. - We resolve the conflict by creating a new macro ASM_OUTPUT_DWARF2_ADDR_CONST - for ports that want to support both DWARF1 and DWARF2. This needs a better - solution. See also the comments in sparc/sp64-elf.h. */ -#ifdef ASM_OUTPUT_DWARF2_ADDR_CONST -#undef ASM_OUTPUT_DWARF_ADDR_CONST -#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,ADDR) \ - ASM_OUTPUT_DWARF2_ADDR_CONST (FILE, ADDR) -#endif - -#ifndef ASM_OUTPUT_DWARF_ADDR_CONST -#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,ADDR) \ - fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, (ADDR)) -#endif - -#ifndef ASM_OUTPUT_DWARF_OFFSET4 -#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \ - do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \ - assemble_name (FILE, LABEL); \ - } while (0) -#endif - -#ifndef ASM_OUTPUT_DWARF_OFFSET -#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \ - do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \ - assemble_name (FILE, LABEL); \ - } while (0) -#endif - -#ifndef ASM_OUTPUT_DWARF_DATA2 -#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \ - fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) (VALUE)) -#endif - -#ifndef ASM_OUTPUT_DWARF_DATA4 -#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \ - fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_INT_ASM_OP, (unsigned) (VALUE)) -#endif - -#ifndef ASM_OUTPUT_DWARF_DATA -#define ASM_OUTPUT_DWARF_DATA(FILE,VALUE) \ - fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_OFFSET_ASM_OP, \ - (unsigned long) (VALUE)) -#endif - -#ifndef ASM_OUTPUT_DWARF_ADDR_DATA -#define ASM_OUTPUT_DWARF_ADDR_DATA(FILE,VALUE) \ - fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_WORD_ASM_OP, \ - (unsigned long) (VALUE)) -#endif - -#ifndef ASM_OUTPUT_DWARF_DATA8 -#define ASM_OUTPUT_DWARF_DATA8(FILE,HIGH_VALUE,LOW_VALUE) \ - do { \ - if (WORDS_BIG_ENDIAN) \ - { \ - fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (HIGH_VALUE));\ - fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (LOW_VALUE));\ - } \ - else \ - { \ - fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (LOW_VALUE)); \ - fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (HIGH_VALUE)); \ - } \ - } while (0) -#endif - -#else /* UNALIGNED_INT_ASM_OP */ - -/* We don't have unaligned support, let's hope the normal output works for - .debug_frame. */ - -#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \ - assemble_integer (gen_rtx_SYMBOL_REF (Pmode, LABEL), PTR_SIZE, 1) - -#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \ - assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1) - -#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \ - assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1) - -#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \ - assemble_integer (gen_rtx_MINUS (HImode, \ - gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ - gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ - 2, 1) - -#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \ - assemble_integer (gen_rtx_MINUS (SImode, \ - gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ - gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ - 4, 1) - -#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \ - assemble_integer (gen_rtx_MINUS (Pmode, \ - gen_rtx_SYMBOL_REF (Pmode, LABEL1), \ - gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \ - PTR_SIZE, 1) - -#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \ - ASM_OUTPUT_DWARF_DELTA4 (FILE,LABEL1,LABEL2) - -#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \ - assemble_integer (GEN_INT (VALUE), 4, 1) - -#endif /* UNALIGNED_INT_ASM_OP */ - -#ifdef SET_ASM_OP -#ifndef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL -#define ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL(FILE, SY, HI, LO) \ - do { \ - fprintf (FILE, "\t%s\t", SET_ASM_OP); \ - assemble_name (FILE, SY); \ - fputc (',', FILE); \ - assemble_name (FILE, HI); \ - fputc ('-', FILE); \ - assemble_name (FILE, LO); \ - } while (0) -#endif -#endif /* SET_ASM_OP */ - -/* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing - newline is produced. When flag_debug_asm is asserted, we add commentary - at the end of the line, so we must avoid output of a newline here. */ -#ifndef ASM_OUTPUT_DWARF_STRING -#define ASM_OUTPUT_DWARF_STRING(FILE,P) \ - do { \ - register int slen = strlen(P); \ - register char *p = (P); \ - register int i; \ - fprintf (FILE, "\t.ascii \""); \ - for (i = 0; i < slen; i++) \ - { \ - register int c = p[i]; \ - if (c == '\"' || c == '\\') \ - putc ('\\', FILE); \ - if (c >= ' ' && c < 0177) \ - putc (c, FILE); \ - else \ - { \ - fprintf (FILE, "\\%o", c); \ - } \ - } \ - fprintf (FILE, "\\0\""); \ - } \ - while (0) -#endif - -/* The DWARF 2 CFA column which tracks the return address. Normally this - is the column for PC, or the first column after all of the hard - registers. */ -#ifndef DWARF_FRAME_RETURN_COLUMN -#ifdef PC_REGNUM -#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (PC_REGNUM) -#else -#define DWARF_FRAME_RETURN_COLUMN FIRST_PSEUDO_REGISTER -#endif -#endif - -/* The mapping from gcc register number to DWARF 2 CFA column number. By - default, we just provide columns for all registers. */ -#ifndef DWARF_FRAME_REGNUM -#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG) -#endif - -/* Hook used by __throw. */ - -rtx -expand_builtin_dwarf_fp_regnum () -{ - return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM)); -} - -/* The offset from the incoming value of %sp to the top of the stack frame - for the current function. */ -#ifndef INCOMING_FRAME_SP_OFFSET -#define INCOMING_FRAME_SP_OFFSET 0 -#endif - -/* Return a pointer to a copy of the section string name S with all - attributes stripped off, and an asterisk prepended (for assemble_name). */ - -static inline char * -stripattributes (s) - char *s; -{ - char *stripped = xmalloc (strlen (s) + 2); - char *p = stripped; - - *p++ = '*'; - - while (*s && *s != ',') - *p++ = *s++; - - *p = '\0'; - return stripped; -} - -/* Return the register number described by a given RTL node. */ - -static unsigned -reg_number (rtl) - register rtx rtl; -{ - register unsigned regno = REGNO (rtl); - - if (regno >= FIRST_PSEUDO_REGISTER) - { - warning ("internal regno botch: regno = %d\n", regno); - regno = 0; - } - - regno = DBX_REGISTER_NUMBER (regno); - return regno; -} - -struct reg_size_range -{ - int beg; - int end; - int size; -}; - -/* Given a register number in REG_TREE, return an rtx for its size in bytes. - We do this in kind of a roundabout way, by building up a list of - register size ranges and seeing where our register falls in one of those - ranges. We need to do it this way because REG_TREE is not a constant, - and the target macros were not designed to make this task easy. */ - -rtx -expand_builtin_dwarf_reg_size (reg_tree, target) - tree reg_tree; - rtx target; -{ - enum machine_mode mode; - int size; - struct reg_size_range ranges[5]; - tree t, t2; - - int i = 0; - int n_ranges = 0; - int last_size = -1; - - for (; i < FIRST_PSEUDO_REGISTER; ++i) - { - /* The return address is out of order on the MIPS, and we don't use - copy_reg for it anyway, so we don't care here how large it is. */ - if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN) - continue; - - mode = reg_raw_mode[i]; - - /* CCmode is arbitrarily given a size of 4 bytes. It is more useful - to use the same size as word_mode, since that reduces the number - of ranges we need. It should not matter, since the result should - never be used for a condition code register anyways. */ - if (GET_MODE_CLASS (mode) == MODE_CC) - mode = word_mode; - - size = GET_MODE_SIZE (mode); - - /* If this register is not valid in the specified mode and - we have a previous size, use that for the size of this - register to avoid making junk tiny ranges. */ - if (! HARD_REGNO_MODE_OK (i, mode) && last_size != -1) - size = last_size; - - if (size != last_size) - { - ranges[n_ranges].beg = i; - ranges[n_ranges].size = last_size = size; - ++n_ranges; - if (n_ranges >= 5) - abort (); - } - ranges[n_ranges-1].end = i; - } - - /* The usual case: fp regs surrounded by general regs. */ - if (n_ranges == 3 && ranges[0].size == ranges[2].size) - { - if ((DWARF_FRAME_REGNUM (ranges[1].end) - - DWARF_FRAME_REGNUM (ranges[1].beg)) - != ranges[1].end - ranges[1].beg) - abort (); - t = fold (build (GE_EXPR, integer_type_node, reg_tree, - build_int_2 (DWARF_FRAME_REGNUM (ranges[1].beg), 0))); - t2 = fold (build (LE_EXPR, integer_type_node, reg_tree, - build_int_2 (DWARF_FRAME_REGNUM (ranges[1].end), 0))); - t = fold (build (TRUTH_ANDIF_EXPR, integer_type_node, t, t2)); - t = fold (build (COND_EXPR, integer_type_node, t, - build_int_2 (ranges[1].size, 0), - build_int_2 (ranges[0].size, 0))); - } - else - { - /* Initialize last_end to be larger than any possible - DWARF_FRAME_REGNUM. */ - int last_end = 0x7fffffff; - --n_ranges; - t = build_int_2 (ranges[n_ranges].size, 0); - do - { - int beg = DWARF_FRAME_REGNUM (ranges[n_ranges].beg); - int end = DWARF_FRAME_REGNUM (ranges[n_ranges].end); - if (beg < 0) - continue; - if (end >= last_end) - abort (); - last_end = end; - if (end - beg != ranges[n_ranges].end - ranges[n_ranges].beg) - abort (); - t2 = fold (build (LE_EXPR, integer_type_node, reg_tree, - build_int_2 (end, 0))); - t = fold (build (COND_EXPR, integer_type_node, t2, - build_int_2 (ranges[n_ranges].size, 0), t)); - } - while (--n_ranges >= 0); - } - return expand_expr (t, target, Pmode, 0); -} - -/* Convert a DWARF call frame info. operation to its string name */ - -static char * -dwarf_cfi_name (cfi_opc) - register unsigned cfi_opc; -{ - switch (cfi_opc) - { - case DW_CFA_advance_loc: - return "DW_CFA_advance_loc"; - case DW_CFA_offset: - return "DW_CFA_offset"; - case DW_CFA_restore: - return "DW_CFA_restore"; - case DW_CFA_nop: - return "DW_CFA_nop"; - case DW_CFA_set_loc: - return "DW_CFA_set_loc"; - case DW_CFA_advance_loc1: - return "DW_CFA_advance_loc1"; - case DW_CFA_advance_loc2: - return "DW_CFA_advance_loc2"; - case DW_CFA_advance_loc4: - return "DW_CFA_advance_loc4"; - case DW_CFA_offset_extended: - return "DW_CFA_offset_extended"; - case DW_CFA_restore_extended: - return "DW_CFA_restore_extended"; - case DW_CFA_undefined: - return "DW_CFA_undefined"; - case DW_CFA_same_value: - return "DW_CFA_same_value"; - case DW_CFA_register: - return "DW_CFA_register"; - case DW_CFA_remember_state: - return "DW_CFA_remember_state"; - case DW_CFA_restore_state: - return "DW_CFA_restore_state"; - case DW_CFA_def_cfa: - return "DW_CFA_def_cfa"; - case DW_CFA_def_cfa_register: - return "DW_CFA_def_cfa_register"; - case DW_CFA_def_cfa_offset: - return "DW_CFA_def_cfa_offset"; - - /* SGI/MIPS specific */ - case DW_CFA_MIPS_advance_loc8: - return "DW_CFA_MIPS_advance_loc8"; - - /* GNU extensions */ - case DW_CFA_GNU_window_save: - return "DW_CFA_GNU_window_save"; - case DW_CFA_GNU_args_size: - return "DW_CFA_GNU_args_size"; - case DW_CFA_GNU_negative_offset_extended: - return "DW_CFA_GNU_negative_offset_extended"; - - default: - return "DW_CFA_<unknown>"; - } -} - -/* Return a pointer to a newly allocated Call Frame Instruction. */ - -static inline dw_cfi_ref -new_cfi () -{ - register dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node)); - - cfi->dw_cfi_next = NULL; - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0; - cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0; - - return cfi; -} - -/* Add a Call Frame Instruction to list of instructions. */ - -static inline void -add_cfi (list_head, cfi) - register dw_cfi_ref *list_head; - register dw_cfi_ref cfi; -{ - register dw_cfi_ref *p; - - /* Find the end of the chain. */ - for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next) - ; - - *p = cfi; -} - -/* Generate a new label for the CFI info to refer to. */ - -char * -dwarf2out_cfi_label () -{ - static char label[20]; - static unsigned long label_num = 0; - - ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", label_num++); - ASM_OUTPUT_LABEL (asm_out_file, label); - - return label; -} - -/* Add CFI to the current fde at the PC value indicated by LABEL if specified, - or to the CIE if LABEL is NULL. */ - -static void -add_fde_cfi (label, cfi) - register char *label; - register dw_cfi_ref cfi; -{ - if (label) - { - register dw_fde_ref fde = &fde_table[fde_table_in_use - 1]; - - if (*label == 0) - label = dwarf2out_cfi_label (); - - if (fde->dw_fde_current_label == NULL - || strcmp (label, fde->dw_fde_current_label) != 0) - { - register dw_cfi_ref xcfi; - - fde->dw_fde_current_label = label = xstrdup (label); - - /* Set the location counter to the new label. */ - xcfi = new_cfi (); - xcfi->dw_cfi_opc = DW_CFA_advance_loc4; - xcfi->dw_cfi_oprnd1.dw_cfi_addr = label; - add_cfi (&fde->dw_fde_cfi, xcfi); - } - - add_cfi (&fde->dw_fde_cfi, cfi); - } - - else - add_cfi (&cie_cfi_head, cfi); -} - -/* Subroutine of lookup_cfa. */ - -static inline void -lookup_cfa_1 (cfi, regp, offsetp) - register dw_cfi_ref cfi; - register unsigned long *regp; - register long *offsetp; -{ - switch (cfi->dw_cfi_opc) - { - case DW_CFA_def_cfa_offset: - *offsetp = cfi->dw_cfi_oprnd1.dw_cfi_offset; - break; - case DW_CFA_def_cfa_register: - *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; - break; - case DW_CFA_def_cfa: - *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num; - *offsetp = cfi->dw_cfi_oprnd2.dw_cfi_offset; - break; - default: - break; - } -} - -/* Find the previous value for the CFA. */ - -static void -lookup_cfa (regp, offsetp) - register unsigned long *regp; - register long *offsetp; -{ - register dw_cfi_ref cfi; - - *regp = (unsigned long) -1; - *offsetp = 0; - - for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next) - lookup_cfa_1 (cfi, regp, offsetp); - - if (fde_table_in_use) - { - register dw_fde_ref fde = &fde_table[fde_table_in_use - 1]; - for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next) - lookup_cfa_1 (cfi, regp, offsetp); - } -} - -/* The current rule for calculating the DWARF2 canonical frame address. */ -static unsigned long cfa_reg; -static long cfa_offset; - -/* The register used for saving registers to the stack, and its offset - from the CFA. */ -static unsigned cfa_store_reg; -static long cfa_store_offset; - -/* The running total of the size of arguments pushed onto the stack. */ -static long args_size; - -/* The last args_size we actually output. */ -static long old_args_size; - -/* Entry point to update the canonical frame address (CFA). - LABEL is passed to add_fde_cfi. The value of CFA is now to be - calculated from REG+OFFSET. */ - -void -dwarf2out_def_cfa (label, reg, offset) - register char *label; - register unsigned reg; - register long offset; -{ - register dw_cfi_ref cfi; - unsigned long old_reg; - long old_offset; - - cfa_reg = reg; - cfa_offset = offset; - if (cfa_store_reg == reg) - cfa_store_offset = offset; - - reg = DWARF_FRAME_REGNUM (reg); - lookup_cfa (&old_reg, &old_offset); - - if (reg == old_reg && offset == old_offset) - return; - - cfi = new_cfi (); - - if (reg == old_reg) - { - cfi->dw_cfi_opc = DW_CFA_def_cfa_offset; - cfi->dw_cfi_oprnd1.dw_cfi_offset = offset; - } - -#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */ - else if (offset == old_offset && old_reg != (unsigned long) -1) - { - cfi->dw_cfi_opc = DW_CFA_def_cfa_register; - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; - } -#endif - - else - { - cfi->dw_cfi_opc = DW_CFA_def_cfa; - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; - cfi->dw_cfi_oprnd2.dw_cfi_offset = offset; - } - - add_fde_cfi (label, cfi); -} - -/* Add the CFI for saving a register. REG is the CFA column number. - LABEL is passed to add_fde_cfi. - If SREG is -1, the register is saved at OFFSET from the CFA; - otherwise it is saved in SREG. */ - -static void -reg_save (label, reg, sreg, offset) - register char * label; - register unsigned reg; - register unsigned sreg; - register long offset; -{ - register dw_cfi_ref cfi = new_cfi (); - - cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg; - - /* The following comparison is correct. -1 is used to indicate that - the value isn't a register number. */ - if (sreg == (unsigned int) -1) - { - if (reg & ~0x3f) - /* The register number won't fit in 6 bits, so we have to use - the long form. */ - cfi->dw_cfi_opc = DW_CFA_offset_extended; - else - cfi->dw_cfi_opc = DW_CFA_offset; - - offset /= DWARF_CIE_DATA_ALIGNMENT; - if (offset < 0) - { - cfi->dw_cfi_opc = DW_CFA_GNU_negative_offset_extended; - offset = -offset; - } - cfi->dw_cfi_oprnd2.dw_cfi_offset = offset; - } - else - { - cfi->dw_cfi_opc = DW_CFA_register; - cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg; - } - - add_fde_cfi (label, cfi); -} - -/* Add the CFI for saving a register window. LABEL is passed to reg_save. - This CFI tells the unwinder that it needs to restore the window registers - from the previous frame's window save area. - - ??? Perhaps we should note in the CIE where windows are saved (instead of - assuming 0(cfa)) and what registers are in the window. */ - -void -dwarf2out_window_save (label) - register char * label; -{ - register dw_cfi_ref cfi = new_cfi (); - cfi->dw_cfi_opc = DW_CFA_GNU_window_save; - add_fde_cfi (label, cfi); -} - -/* Add a CFI to update the running total of the size of arguments - pushed onto the stack. */ - -void -dwarf2out_args_size (label, size) - char *label; - long size; -{ - register dw_cfi_ref cfi; - - if (size == old_args_size) - return; - old_args_size = size; - - cfi = new_cfi (); - cfi->dw_cfi_opc = DW_CFA_GNU_args_size; - cfi->dw_cfi_oprnd1.dw_cfi_offset = size; - add_fde_cfi (label, cfi); -} - -/* Entry point for saving a register to the stack. REG is the GCC register - number. LABEL and OFFSET are passed to reg_save. */ - -void -dwarf2out_reg_save (label, reg, offset) - register char * label; - register unsigned reg; - register long offset; -{ - reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset); -} - -/* Entry point for saving the return address in the stack. - LABEL and OFFSET are passed to reg_save. */ - -void -dwarf2out_return_save (label, offset) - register char * label; - register long offset; -{ - reg_save (label, DWARF_FRAME_RETURN_COLUMN, -1, offset); -} - -/* Entry point for saving the return address in a register. - LABEL and SREG are passed to reg_save. */ - -void -dwarf2out_return_reg (label, sreg) - register char * label; - register unsigned sreg; -{ - reg_save (label, DWARF_FRAME_RETURN_COLUMN, sreg, 0); -} - -/* Record the initial position of the return address. RTL is - INCOMING_RETURN_ADDR_RTX. */ - -static void -initial_return_save (rtl) - register rtx rtl; -{ - unsigned int reg = (unsigned int) -1; - long offset = 0; - - switch (GET_CODE (rtl)) - { - case REG: - /* RA is in a register. */ - reg = reg_number (rtl); - break; - case MEM: - /* RA is on the stack. */ - rtl = XEXP (rtl, 0); - switch (GET_CODE (rtl)) - { - case REG: - if (REGNO (rtl) != STACK_POINTER_REGNUM) - abort (); - offset = 0; - break; - case PLUS: - if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM) - abort (); - offset = INTVAL (XEXP (rtl, 1)); - break; - case MINUS: - if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM) - abort (); - offset = -INTVAL (XEXP (rtl, 1)); - break; - default: - abort (); - } - break; - case PLUS: - /* The return address is at some offset from any value we can - actually load. For instance, on the SPARC it is in %i7+8. Just - ignore the offset for now; it doesn't matter for unwinding frames. */ - if (GET_CODE (XEXP (rtl, 1)) != CONST_INT) - abort (); - initial_return_save (XEXP (rtl, 0)); - return; - default: - abort (); - } - - reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa_offset); -} - -/* Check INSN to see if it looks like a push or a stack adjustment, and - make a note of it if it does. EH uses this information to find out how - much extra space it needs to pop off the stack. */ - -static void -dwarf2out_stack_adjust (insn) - rtx insn; -{ - long offset; - char *label; - - if (! asynchronous_exceptions && GET_CODE (insn) == CALL_INSN) - { - /* Extract the size of the args from the CALL rtx itself. */ - - insn = PATTERN (insn); - if (GET_CODE (insn) == PARALLEL) - insn = XVECEXP (insn, 0, 0); - if (GET_CODE (insn) == SET) - insn = SET_SRC (insn); - assert (GET_CODE (insn) == CALL); - dwarf2out_args_size ("", INTVAL (XEXP (insn, 1))); - return; - } - - /* If only calls can throw, and we have a frame pointer, - save up adjustments until we see the CALL_INSN. */ - else if (! asynchronous_exceptions - && cfa_reg != STACK_POINTER_REGNUM) - return; - - if (GET_CODE (insn) == BARRIER) - { - /* When we see a BARRIER, we know to reset args_size to 0. Usually - the compiler will have already emitted a stack adjustment, but - doesn't bother for calls to noreturn functions. */ -#ifdef STACK_GROWS_DOWNWARD - offset = -args_size; -#else - offset = args_size; -#endif - } - else if (GET_CODE (PATTERN (insn)) == SET) - { - rtx src, dest; - enum rtx_code code; - - insn = PATTERN (insn); - src = SET_SRC (insn); - dest = SET_DEST (insn); - - if (dest == stack_pointer_rtx) - { - /* (set (reg sp) (plus (reg sp) (const_int))) */ - code = GET_CODE (src); - if (! (code == PLUS || code == MINUS) - || XEXP (src, 0) != stack_pointer_rtx - || GET_CODE (XEXP (src, 1)) != CONST_INT) - return; - - offset = INTVAL (XEXP (src, 1)); - } - else if (GET_CODE (dest) == MEM) - { - /* (set (mem (pre_dec (reg sp))) (foo)) */ - src = XEXP (dest, 0); - code = GET_CODE (src); - - if (! (code == PRE_DEC || code == PRE_INC) - || XEXP (src, 0) != stack_pointer_rtx) - return; - - offset = GET_MODE_SIZE (GET_MODE (dest)); - } - else - return; - - if (code == PLUS || code == PRE_INC) - offset = -offset; - } - else - return; - - if (offset == 0) - return; - - if (cfa_reg == STACK_POINTER_REGNUM) - cfa_offset += offset; - -#ifndef STACK_GROWS_DOWNWARD - offset = -offset; -#endif - args_size += offset; - if (args_size < 0) - args_size = 0; - - label = dwarf2out_cfi_label (); - dwarf2out_def_cfa (label, cfa_reg, cfa_offset); - dwarf2out_args_size (label, args_size); -} - -/* A temporary register used in adjusting SP or setting up the store_reg. */ -static unsigned cfa_temp_reg; - -/* A temporary value used in adjusting SP or setting up the store_reg. */ -static long cfa_temp_value; - -/* Record call frame debugging information for an expression, which either - sets SP or FP (adjusting how we calculate the frame address) or saves a - register to the stack. */ - -static void -dwarf2out_frame_debug_expr (expr, label) - rtx expr; - char *label; -{ - rtx src, dest; - long offset; - - /* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of - the PARALLEL independantly. The first element is always processed if - it is a SET. This is for backward compatability. Other elements - are processed only if they are SETs and the RTX_FRAME_RELATED_P - flag is set in them. */ - - if (GET_CODE (expr) == PARALLEL) - { - int par_index; - int limit = XVECLEN (expr, 0); - - for (par_index = 0; par_index < limit; par_index++) - { - rtx x = XVECEXP (expr, 0, par_index); - - if (GET_CODE (x) == SET && - (RTX_FRAME_RELATED_P (x) || par_index == 0)) - dwarf2out_frame_debug_expr (x, label); - } - return; - } - - if (GET_CODE (expr) != SET) - abort (); - - src = SET_SRC (expr); - dest = SET_DEST (expr); - - switch (GET_CODE (dest)) - { - case REG: - /* Update the CFA rule wrt SP or FP. Make sure src is - relative to the current CFA register. */ - switch (GET_CODE (src)) - { - /* Setting FP from SP. */ - case REG: - if (cfa_reg != (unsigned) REGNO (src)) - abort (); - if (REGNO (dest) != STACK_POINTER_REGNUM - && !(frame_pointer_needed - && REGNO (dest) == HARD_FRAME_POINTER_REGNUM)) - abort (); - cfa_reg = REGNO (dest); - break; - - case PLUS: - case MINUS: - if (dest == stack_pointer_rtx) - { - /* Adjusting SP. */ - switch (GET_CODE (XEXP (src, 1))) - { - case CONST_INT: - offset = INTVAL (XEXP (src, 1)); - break; - case REG: - if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp_reg) - abort (); - offset = cfa_temp_value; - break; - default: - abort (); - } - - if (XEXP (src, 0) == hard_frame_pointer_rtx) - { - /* Restoring SP from FP in the epilogue. */ - if (cfa_reg != (unsigned) HARD_FRAME_POINTER_REGNUM) - abort (); - cfa_reg = STACK_POINTER_REGNUM; - } - else if (XEXP (src, 0) != stack_pointer_rtx) - abort (); - - if (GET_CODE (src) == PLUS) - offset = -offset; - if (cfa_reg == STACK_POINTER_REGNUM) - cfa_offset += offset; - if (cfa_store_reg == STACK_POINTER_REGNUM) - cfa_store_offset += offset; - } - else if (dest == hard_frame_pointer_rtx) - { - /* Either setting the FP from an offset of the SP, - or adjusting the FP */ - if (! frame_pointer_needed - || REGNO (dest) != HARD_FRAME_POINTER_REGNUM) - abort (); - - if (XEXP (src, 0) == stack_pointer_rtx - && GET_CODE (XEXP (src, 1)) == CONST_INT) - { - if (cfa_reg != STACK_POINTER_REGNUM) - abort (); - offset = INTVAL (XEXP (src, 1)); - if (GET_CODE (src) == PLUS) - offset = -offset; - cfa_offset += offset; - cfa_reg = HARD_FRAME_POINTER_REGNUM; - } - else if (XEXP (src, 0) == hard_frame_pointer_rtx - && GET_CODE (XEXP (src, 1)) == CONST_INT) - { - if (cfa_reg != (unsigned) HARD_FRAME_POINTER_REGNUM) - abort (); - offset = INTVAL (XEXP (src, 1)); - if (GET_CODE (src) == PLUS) - offset = -offset; - cfa_offset += offset; - } - - else - abort(); - } - else - { - if (GET_CODE (src) != PLUS - || XEXP (src, 1) != stack_pointer_rtx) - abort (); - if (GET_CODE (XEXP (src, 0)) != REG - || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg) - abort (); - if (cfa_reg != STACK_POINTER_REGNUM) - abort (); - cfa_store_reg = REGNO (dest); - cfa_store_offset = cfa_offset - cfa_temp_value; - } - break; - - case CONST_INT: - cfa_temp_reg = REGNO (dest); - cfa_temp_value = INTVAL (src); - break; - - case IOR: - if (GET_CODE (XEXP (src, 0)) != REG - || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg - || (unsigned) REGNO (dest) != cfa_temp_reg - || GET_CODE (XEXP (src, 1)) != CONST_INT) - abort (); - cfa_temp_value |= INTVAL (XEXP (src, 1)); - break; - - default: - abort (); - } - dwarf2out_def_cfa (label, cfa_reg, cfa_offset); - break; - - case MEM: - /* Saving a register to the stack. Make sure dest is relative to the - CFA register. */ - if (GET_CODE (src) != REG) - abort (); - switch (GET_CODE (XEXP (dest, 0))) - { - /* With a push. */ - case PRE_INC: - case PRE_DEC: - offset = GET_MODE_SIZE (GET_MODE (dest)); - if (GET_CODE (XEXP (dest, 0)) == PRE_INC) - offset = -offset; - - if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM - || cfa_store_reg != STACK_POINTER_REGNUM) - abort (); - cfa_store_offset += offset; - if (cfa_reg == STACK_POINTER_REGNUM) - cfa_offset = cfa_store_offset; - - offset = -cfa_store_offset; - break; - - /* With an offset. */ - case PLUS: - case MINUS: - offset = INTVAL (XEXP (XEXP (dest, 0), 1)); - if (GET_CODE (XEXP (dest, 0)) == MINUS) - offset = -offset; - - if (cfa_store_reg != (unsigned) REGNO (XEXP (XEXP (dest, 0), 0))) - abort (); - offset -= cfa_store_offset; - break; - - /* Without an offset. */ - case REG: - if (cfa_store_reg != (unsigned) REGNO (XEXP (dest, 0))) - abort(); - offset = -cfa_store_offset; - break; - - default: - abort (); - } - dwarf2out_def_cfa (label, cfa_reg, cfa_offset); - dwarf2out_reg_save (label, REGNO (src), offset); - break; - - default: - abort (); - } -} - - -/* Record call frame debugging information for INSN, which either - sets SP or FP (adjusting how we calculate the frame address) or saves a - register to the stack. If INSN is NULL_RTX, initialize our state. */ - -void -dwarf2out_frame_debug (insn) - rtx insn; -{ - char *label; - rtx src; - - if (insn == NULL_RTX) - { - /* Set up state for generating call frame debug info. */ - lookup_cfa (&cfa_reg, &cfa_offset); - if (cfa_reg != DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM)) - abort (); - cfa_reg = STACK_POINTER_REGNUM; - cfa_store_reg = cfa_reg; - cfa_store_offset = cfa_offset; - cfa_temp_reg = -1; - cfa_temp_value = 0; - return; - } - - if (! RTX_FRAME_RELATED_P (insn)) - { - dwarf2out_stack_adjust (insn); - return; - } - - label = dwarf2out_cfi_label (); - - src = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX); - if (src) - insn = XEXP (src, 0); - else - insn = PATTERN (insn); - - dwarf2out_frame_debug_expr (insn, label); -} - -/* Return the size of an unsigned LEB128 quantity. */ - -static inline unsigned long -size_of_uleb128 (value) - register unsigned long value; -{ - register unsigned long size = 0; - register unsigned byte; - - do - { - byte = (value & 0x7f); - value >>= 7; - size += 1; - } - while (value != 0); - - return size; -} - -/* Return the size of a signed LEB128 quantity. */ - -static inline unsigned long -size_of_sleb128 (value) - register long value; -{ - register unsigned long size = 0; - register unsigned byte; - - do - { - byte = (value & 0x7f); - value >>= 7; - size += 1; - } - while (!(((value == 0) && ((byte & 0x40) == 0)) - || ((value == -1) && ((byte & 0x40) != 0)))); - - return size; -} - -/* Output an unsigned LEB128 quantity. */ - -static void -output_uleb128 (value) - register unsigned long value; -{ - unsigned long save_value = value; - - fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP); - do - { - register unsigned byte = (value & 0x7f); - value >>= 7; - if (value != 0) - /* More bytes to follow. */ - byte |= 0x80; - - fprintf (asm_out_file, "0x%x", byte); - if (value != 0) - fprintf (asm_out_file, ","); - } - while (value != 0); - - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s ULEB128 0x%lx", ASM_COMMENT_START, save_value); -} - -/* Output an signed LEB128 quantity. */ - -static void -output_sleb128 (value) - register long value; -{ - register int more; - register unsigned byte; - long save_value = value; - - fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP); - do - { - byte = (value & 0x7f); - /* arithmetic shift */ - value >>= 7; - more = !((((value == 0) && ((byte & 0x40) == 0)) - || ((value == -1) && ((byte & 0x40) != 0)))); - if (more) - byte |= 0x80; - - fprintf (asm_out_file, "0x%x", byte); - if (more) - fprintf (asm_out_file, ","); - } - - while (more); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s SLEB128 %ld", ASM_COMMENT_START, save_value); -} - -/* Output a Call Frame Information opcode and its operand(s). */ - -static void -output_cfi (cfi, fde) - register dw_cfi_ref cfi; - register dw_fde_ref fde; -{ - if (cfi->dw_cfi_opc == DW_CFA_advance_loc) - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, - cfi->dw_cfi_opc - | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_CFA_advance_loc 0x%lx", - ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset); - fputc ('\n', asm_out_file); - } - - else if (cfi->dw_cfi_opc == DW_CFA_offset) - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, - cfi->dw_cfi_opc - | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_CFA_offset, column 0x%lx", - ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num); - - fputc ('\n', asm_out_file); - output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset); - fputc ('\n', asm_out_file); - } - else if (cfi->dw_cfi_opc == DW_CFA_restore) - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, - cfi->dw_cfi_opc - | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_CFA_restore, column 0x%lx", - ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num); - - fputc ('\n', asm_out_file); - } - else - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, cfi->dw_cfi_opc); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, - dwarf_cfi_name (cfi->dw_cfi_opc)); - - fputc ('\n', asm_out_file); - switch (cfi->dw_cfi_opc) - { - case DW_CFA_set_loc: - ASM_OUTPUT_DWARF_ADDR (asm_out_file, cfi->dw_cfi_oprnd1.dw_cfi_addr); - fputc ('\n', asm_out_file); - break; - case DW_CFA_advance_loc1: - ASM_OUTPUT_DWARF_DELTA1 (asm_out_file, - cfi->dw_cfi_oprnd1.dw_cfi_addr, - fde->dw_fde_current_label); - fputc ('\n', asm_out_file); - fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; - break; - case DW_CFA_advance_loc2: - ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, - cfi->dw_cfi_oprnd1.dw_cfi_addr, - fde->dw_fde_current_label); - fputc ('\n', asm_out_file); - fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; - break; - case DW_CFA_advance_loc4: - ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, - cfi->dw_cfi_oprnd1.dw_cfi_addr, - fde->dw_fde_current_label); - fputc ('\n', asm_out_file); - fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; - break; -#ifdef MIPS_DEBUGGING_INFO - case DW_CFA_MIPS_advance_loc8: - /* TODO: not currently implemented. */ - abort (); - break; -#endif - case DW_CFA_offset_extended: - case DW_CFA_GNU_negative_offset_extended: - case DW_CFA_def_cfa: - output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); - fputc ('\n', asm_out_file); - output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset); - fputc ('\n', asm_out_file); - break; - case DW_CFA_restore_extended: - case DW_CFA_undefined: - output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); - fputc ('\n', asm_out_file); - break; - case DW_CFA_same_value: - case DW_CFA_def_cfa_register: - output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); - fputc ('\n', asm_out_file); - break; - case DW_CFA_register: - output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num); - fputc ('\n', asm_out_file); - output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num); - fputc ('\n', asm_out_file); - break; - case DW_CFA_def_cfa_offset: - output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset); - fputc ('\n', asm_out_file); - break; - case DW_CFA_GNU_window_save: - break; - case DW_CFA_GNU_args_size: - output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset); - fputc ('\n', asm_out_file); - break; - default: - break; - } - } -} - -#if !defined (EH_FRAME_SECTION) -#if defined (EH_FRAME_SECTION_ASM_OP) -#define EH_FRAME_SECTION() eh_frame_section(); -#else -#if defined (ASM_OUTPUT_SECTION_NAME) -#define EH_FRAME_SECTION() \ - do { \ - named_section (NULL_TREE, ".eh_frame", 0); \ - } while (0) -#endif -#endif -#endif - -/* If we aren't using crtstuff to run ctors, don't use it for EH. */ -#if !defined (HAS_INIT_SECTION) && !defined (INIT_SECTION_ASM_OP) -#undef EH_FRAME_SECTION -#endif - -/* Output the call frame information used to used to record information - that relates to calculating the frame pointer, and records the - location of saved registers. */ - -static void -output_call_frame_info (for_eh) - int for_eh; -{ - register unsigned long i; - register dw_fde_ref fde; - register dw_cfi_ref cfi; - char l1[20], l2[20]; -#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL - char ld[20]; -#endif - - /* Do we want to include a pointer to the exception table? */ - int eh_ptr = for_eh && exception_table_p (); - - fputc ('\n', asm_out_file); - - /* We're going to be generating comments, so turn on app. */ - if (flag_debug_asm) - app_enable (); - - if (for_eh) - { -#ifdef EH_FRAME_SECTION - EH_FRAME_SECTION (); -#else - tree label = get_file_function_name ('F'); - - force_data_section (); - ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); - ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label)); - ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label)); -#endif - assemble_label ("__FRAME_BEGIN__"); - } - else - ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION); - - /* Output the CIE. */ - ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh); - ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh); -#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL - ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh); - if (for_eh) - ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld); - else - ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld); -#else - if (for_eh) - ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1); - else - ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1); -#endif - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Length of Common Information Entry", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_LABEL (asm_out_file, l1); - - if (for_eh) - /* Now that the CIE pointer is PC-relative for EH, - use 0 to identify the CIE. */ - ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); - else - ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID); - - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - if (! for_eh && DWARF_OFFSET_SIZE == 8) - { - ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID); - fputc ('\n', asm_out_file); - } - - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - if (eh_ptr) - { - /* The CIE contains a pointer to the exception region info for the - frame. Make the augmentation string three bytes (including the - trailing null) so the pointer is 4-byte aligned. The Solaris ld - can't handle unaligned relocs. */ - if (flag_debug_asm) - { - ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh"); - fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START); - } - else - { - ASM_OUTPUT_ASCII (asm_out_file, "eh", 3); - } - fputc ('\n', asm_out_file); - - ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__"); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s pointer to exception region info", - ASM_COMMENT_START); - } - else - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s CIE Augmentation (none)", - ASM_COMMENT_START); - } - - fputc ('\n', asm_out_file); - output_uleb128 (1); - if (flag_debug_asm) - fprintf (asm_out_file, " (CIE Code Alignment Factor)"); - - fputc ('\n', asm_out_file); - output_sleb128 (DWARF_CIE_DATA_ALIGNMENT); - if (flag_debug_asm) - fprintf (asm_out_file, " (CIE Data Alignment Factor)"); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - - for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next) - output_cfi (cfi, NULL); - - /* Pad the CIE out to an address sized boundary. */ - ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); - ASM_OUTPUT_LABEL (asm_out_file, l2); -#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL - ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START); - fputc ('\n', asm_out_file); -#endif - - /* Loop through all of the FDE's. */ - for (i = 0; i < fde_table_in_use; ++i) - { - fde = &fde_table[i]; - - ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i*2); - ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i*2); -#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL - ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i*2); - if (for_eh) - ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld); - else - ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld); -#else - if (for_eh) - ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1); - else - ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1); -#endif - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START); - fputc ('\n', asm_out_file); - ASM_OUTPUT_LABEL (asm_out_file, l1); - - /* ??? This always emits a 4 byte offset when for_eh is true, but it - emits a target dependent sized offset when for_eh is not true. - This inconsistency may confuse gdb. The only case where we need a - non-4 byte offset is for the Irix6 N64 ABI, so we may lose SGI - compatibility if we emit a 4 byte offset. We need a 4 byte offset - though in order to be compatible with the dwarf_fde struct in frame.c. - If the for_eh case is changed, then the struct in frame.c has - to be adjusted appropriately. */ - if (for_eh) - ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l1, "__FRAME_BEGIN__"); - else - ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION)); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, - fde->dw_fde_end, fde->dw_fde_begin); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - - /* Loop through the Call Frame Instructions associated with - this FDE. */ - fde->dw_fde_current_label = fde->dw_fde_begin; - for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) - output_cfi (cfi, fde); - - /* Pad the FDE out to an address sized boundary. */ - ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE)); - ASM_OUTPUT_LABEL (asm_out_file, l2); -#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL - ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START); - fputc ('\n', asm_out_file); -#endif - } -#ifndef EH_FRAME_SECTION - if (for_eh) - { - /* Emit terminating zero for table. */ - ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0); - fputc ('\n', asm_out_file); - } -#endif -#ifdef MIPS_DEBUGGING_INFO - /* Work around Irix 6 assembler bug whereby labels at the end of a section - get a value of 0. Putting .align 0 after the label fixes it. */ - ASM_OUTPUT_ALIGN (asm_out_file, 0); -#endif - - /* Turn off app to make assembly quicker. */ - if (flag_debug_asm) - app_disable (); -} - -/* Output a marker (i.e. a label) for the beginning of a function, before - the prologue. */ - -void -dwarf2out_begin_prologue () -{ - char label[MAX_ARTIFICIAL_LABEL_BYTES]; - register dw_fde_ref fde; - - ++current_funcdef_number; - - function_section (current_function_decl); - ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL, - current_funcdef_number); - ASM_OUTPUT_LABEL (asm_out_file, label); - - /* Expand the fde table if necessary. */ - if (fde_table_in_use == fde_table_allocated) - { - fde_table_allocated += FDE_TABLE_INCREMENT; - fde_table - = (dw_fde_ref) xrealloc (fde_table, - fde_table_allocated * sizeof (dw_fde_node)); - } - - /* Record the FDE associated with this function. */ - current_funcdef_fde = fde_table_in_use; - - /* Add the new FDE at the end of the fde_table. */ - fde = &fde_table[fde_table_in_use++]; - fde->dw_fde_begin = xstrdup (label); - fde->dw_fde_current_label = NULL; - fde->dw_fde_end = NULL; - fde->dw_fde_cfi = NULL; - - args_size = old_args_size = 0; -} - -/* Output a marker (i.e. a label) for the absolute end of the generated code - for a function definition. This gets called *after* the epilogue code has - been generated. */ - -void -dwarf2out_end_epilogue () -{ - dw_fde_ref fde; - char label[MAX_ARTIFICIAL_LABEL_BYTES]; - - /* Output a label to mark the endpoint of the code generated for this - function. */ - ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number); - ASM_OUTPUT_LABEL (asm_out_file, label); - fde = &fde_table[fde_table_in_use - 1]; - fde->dw_fde_end = xstrdup (label); -} - -void -dwarf2out_frame_init () -{ - /* Allocate the initial hunk of the fde_table. */ - fde_table - = (dw_fde_ref) xmalloc (FDE_TABLE_INCREMENT * sizeof (dw_fde_node)); - bzero ((char *) fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node)); - fde_table_allocated = FDE_TABLE_INCREMENT; - fde_table_in_use = 0; - - /* Generate the CFA instructions common to all FDE's. Do it now for the - sake of lookup_cfa. */ - -#ifdef DWARF2_UNWIND_INFO - /* On entry, the Canonical Frame Address is at SP. */ - dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET); - initial_return_save (INCOMING_RETURN_ADDR_RTX); -#endif -} - -void -dwarf2out_frame_finish () -{ - /* Output call frame information. */ -#ifdef MIPS_DEBUGGING_INFO - if (write_symbols == DWARF2_DEBUG) - output_call_frame_info (0); - if (flag_exceptions && ! exceptions_via_longjmp) - output_call_frame_info (1); -#else - if (write_symbols == DWARF2_DEBUG - || (flag_exceptions && ! exceptions_via_longjmp)) - output_call_frame_info (1); -#endif -} - -#endif /* .debug_frame support */ - -/* And now, the support for symbolic debugging information. */ -#ifdef DWARF2_DEBUGGING_INFO - -extern char *getpwd PROTO((void)); - -/* NOTE: In the comments in this file, many references are made to - "Debugging Information Entries". This term is abbreviated as `DIE' - throughout the remainder of this file. */ - -/* An internal representation of the DWARF output is built, and then - walked to generate the DWARF debugging info. The walk of the internal - representation is done after the entire program has been compiled. - The types below are used to describe the internal representation. */ - -/* Each DIE may have a series of attribute/value pairs. Values - can take on several forms. The forms that are used in this - implementation are listed below. */ - -typedef enum -{ - dw_val_class_addr, - dw_val_class_loc, - dw_val_class_const, - dw_val_class_unsigned_const, - dw_val_class_long_long, - dw_val_class_float, - dw_val_class_flag, - dw_val_class_die_ref, - dw_val_class_fde_ref, - dw_val_class_lbl_id, - dw_val_class_lbl_offset, - dw_val_class_str -} -dw_val_class; - -/* Various DIE's use offsets relative to the beginning of the - .debug_info section to refer to each other. */ - -typedef long int dw_offset; - -/* Define typedefs here to avoid circular dependencies. */ - -typedef struct die_struct *dw_die_ref; -typedef struct dw_attr_struct *dw_attr_ref; -typedef struct dw_val_struct *dw_val_ref; -typedef struct dw_line_info_struct *dw_line_info_ref; -typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref; -typedef struct dw_loc_descr_struct *dw_loc_descr_ref; -typedef struct pubname_struct *pubname_ref; -typedef dw_die_ref *arange_ref; - -/* Describe a double word constant value. */ - -typedef struct dw_long_long_struct -{ - unsigned long hi; - unsigned long low; -} -dw_long_long_const; - -/* Describe a floating point constant value. */ - -typedef struct dw_fp_struct -{ - long *array; - unsigned length; -} -dw_float_const; - -/* Each entry in the line_info_table maintains the file and - line number associated with the label generated for that - entry. The label gives the PC value associated with - the line number entry. */ - -typedef struct dw_line_info_struct -{ - unsigned long dw_file_num; - unsigned long dw_line_num; -} -dw_line_info_entry; - -/* Line information for functions in separate sections; each one gets its - own sequence. */ -typedef struct dw_separate_line_info_struct -{ - unsigned long dw_file_num; - unsigned long dw_line_num; - unsigned long function; -} -dw_separate_line_info_entry; - -/* The dw_val_node describes an attribute's value, as it is - represented internally. */ - -typedef struct dw_val_struct -{ - dw_val_class val_class; - union - { - char *val_addr; - dw_loc_descr_ref val_loc; - long int val_int; - long unsigned val_unsigned; - dw_long_long_const val_long_long; - dw_float_const val_float; - dw_die_ref val_die_ref; - unsigned val_fde_index; - char *val_str; - char *val_lbl_id; - unsigned char val_flag; - } - v; -} -dw_val_node; - -/* Locations in memory are described using a sequence of stack machine - operations. */ - -typedef struct dw_loc_descr_struct -{ - dw_loc_descr_ref dw_loc_next; - enum dwarf_location_atom dw_loc_opc; - dw_val_node dw_loc_oprnd1; - dw_val_node dw_loc_oprnd2; -} -dw_loc_descr_node; - -/* Each DIE attribute has a field specifying the attribute kind, - a link to the next attribute in the chain, and an attribute value. - Attributes are typically linked below the DIE they modify. */ - -typedef struct dw_attr_struct -{ - enum dwarf_attribute dw_attr; - dw_attr_ref dw_attr_next; - dw_val_node dw_attr_val; -} -dw_attr_node; - -/* The Debugging Information Entry (DIE) structure */ - -typedef struct die_struct -{ - enum dwarf_tag die_tag; - dw_attr_ref die_attr; - dw_attr_ref die_attr_last; - dw_die_ref die_parent; - dw_die_ref die_child; - dw_die_ref die_child_last; - dw_die_ref die_sib; - dw_offset die_offset; - unsigned long die_abbrev; -} -die_node; - -/* The pubname structure */ - -typedef struct pubname_struct -{ - dw_die_ref die; - char * name; -} -pubname_entry; - -/* The limbo die list structure. */ -typedef struct limbo_die_struct -{ - dw_die_ref die; - struct limbo_die_struct *next; -} -limbo_die_node; - -/* How to start an assembler comment. */ -#ifndef ASM_COMMENT_START -#define ASM_COMMENT_START ";#" -#endif - -/* Define a macro which returns non-zero for a TYPE_DECL which was - implicitly generated for a tagged type. - - Note that unlike the gcc front end (which generates a NULL named - TYPE_DECL node for each complete tagged type, each array type, and - each function type node created) the g++ front end generates a - _named_ TYPE_DECL node for each tagged type node created. - These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to - generate a DW_TAG_typedef DIE for them. */ - -#define TYPE_DECL_IS_STUB(decl) \ - (DECL_NAME (decl) == NULL_TREE \ - || (DECL_ARTIFICIAL (decl) \ - && is_tagged_type (TREE_TYPE (decl)) \ - && ((decl == TYPE_STUB_DECL (TREE_TYPE (decl))) \ - /* This is necessary for stub decls that \ - appear in nested inline functions. */ \ - || (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE \ - && (decl_ultimate_origin (decl) \ - == TYPE_STUB_DECL (TREE_TYPE (decl))))))) - -/* Information concerning the compilation unit's programming - language, and compiler version. */ - -extern int flag_traditional; -extern char *version_string; -extern char *language_string; - -/* Fixed size portion of the DWARF compilation unit header. */ -#define DWARF_COMPILE_UNIT_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 3) - -/* Fixed size portion of debugging line information prolog. */ -#define DWARF_LINE_PROLOG_HEADER_SIZE 5 - -/* Fixed size portion of public names info. */ -#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2) - -/* Fixed size portion of the address range info. */ -#define DWARF_ARANGES_HEADER_SIZE \ - (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, PTR_SIZE * 2) - DWARF_OFFSET_SIZE) - -/* Define the architecture-dependent minimum instruction length (in bytes). - In this implementation of DWARF, this field is used for information - purposes only. Since GCC generates assembly language, we have - no a priori knowledge of how many instruction bytes are generated - for each source line, and therefore can use only the DW_LNE_set_address - and DW_LNS_fixed_advance_pc line information commands. */ - -#ifndef DWARF_LINE_MIN_INSTR_LENGTH -#define DWARF_LINE_MIN_INSTR_LENGTH 4 -#endif - -/* Minimum line offset in a special line info. opcode. - This value was chosen to give a reasonable range of values. */ -#define DWARF_LINE_BASE -10 - -/* First special line opcde - leave room for the standard opcodes. */ -#define DWARF_LINE_OPCODE_BASE 10 - -/* Range of line offsets in a special line info. opcode. */ -#define DWARF_LINE_RANGE (254-DWARF_LINE_OPCODE_BASE+1) - -/* Flag that indicates the initial value of the is_stmt_start flag. - In the present implementation, we do not mark any lines as - the beginning of a source statement, because that information - is not made available by the GCC front-end. */ -#define DWARF_LINE_DEFAULT_IS_STMT_START 1 - -/* This location is used by calc_die_sizes() to keep track - the offset of each DIE within the .debug_info section. */ -static unsigned long next_die_offset; - -/* Record the root of the DIE's built for the current compilation unit. */ -static dw_die_ref comp_unit_die; - -/* A list of DIEs with a NULL parent waiting to be relocated. */ -static limbo_die_node *limbo_die_list = 0; - -/* Pointer to an array of filenames referenced by this compilation unit. */ -static char **file_table; - -/* Total number of entries in the table (i.e. array) pointed to by - `file_table'. This is the *total* and includes both used and unused - slots. */ -static unsigned file_table_allocated; - -/* Number of entries in the file_table which are actually in use. */ -static unsigned file_table_in_use; - -/* Size (in elements) of increments by which we may expand the filename - table. */ -#define FILE_TABLE_INCREMENT 64 - -/* Local pointer to the name of the main input file. Initialized in - dwarf2out_init. */ -static char *primary_filename; - -/* For Dwarf output, we must assign lexical-blocks id numbers in the order in - which their beginnings are encountered. We output Dwarf debugging info - that refers to the beginnings and ends of the ranges of code for each - lexical block. The labels themselves are generated in final.c, which - assigns numbers to the blocks in the same way. */ -static unsigned next_block_number = 2; - -/* A pointer to the base of a table of references to DIE's that describe - declarations. The table is indexed by DECL_UID() which is a unique - number identifying each decl. */ -static dw_die_ref *decl_die_table; - -/* Number of elements currently allocated for the decl_die_table. */ -static unsigned decl_die_table_allocated; - -/* Number of elements in decl_die_table currently in use. */ -static unsigned decl_die_table_in_use; - -/* Size (in elements) of increments by which we may expand the - decl_die_table. */ -#define DECL_DIE_TABLE_INCREMENT 256 - -/* Structure used for the decl_scope table. scope is the current declaration - scope, and previous is the entry that is the parent of this scope. This - is usually but not always the immediately preceeding entry. */ - -typedef struct decl_scope_struct -{ - tree scope; - int previous; -} -decl_scope_node; - -/* A pointer to the base of a table of references to declaration - scopes. This table is a display which tracks the nesting - of declaration scopes at the current scope and containing - scopes. This table is used to find the proper place to - define type declaration DIE's. */ -static decl_scope_node *decl_scope_table; - -/* Number of elements currently allocated for the decl_scope_table. */ -static int decl_scope_table_allocated; - -/* Current level of nesting of declaration scopes. */ -static int decl_scope_depth; - -/* Size (in elements) of increments by which we may expand the - decl_scope_table. */ -#define DECL_SCOPE_TABLE_INCREMENT 64 - -/* A pointer to the base of a list of references to DIE's that - are uniquely identified by their tag, presence/absence of - children DIE's, and list of attribute/value pairs. */ -static dw_die_ref *abbrev_die_table; - -/* Number of elements currently allocated for abbrev_die_table. */ -static unsigned abbrev_die_table_allocated; - -/* Number of elements in type_die_table currently in use. */ -static unsigned abbrev_die_table_in_use; - -/* Size (in elements) of increments by which we may expand the - abbrev_die_table. */ -#define ABBREV_DIE_TABLE_INCREMENT 256 - -/* A pointer to the base of a table that contains line information - for each source code line in .text in the compilation unit. */ -static dw_line_info_ref line_info_table; - -/* Number of elements currently allocated for line_info_table. */ -static unsigned line_info_table_allocated; - -/* Number of elements in separate_line_info_table currently in use. */ -static unsigned separate_line_info_table_in_use; - -/* A pointer to the base of a table that contains line information - for each source code line outside of .text in the compilation unit. */ -static dw_separate_line_info_ref separate_line_info_table; - -/* Number of elements currently allocated for separate_line_info_table. */ -static unsigned separate_line_info_table_allocated; - -/* Number of elements in line_info_table currently in use. */ -static unsigned line_info_table_in_use; - -/* Size (in elements) of increments by which we may expand the - line_info_table. */ -#define LINE_INFO_TABLE_INCREMENT 1024 - -/* A pointer to the base of a table that contains a list of publicly - accessible names. */ -static pubname_ref pubname_table; - -/* Number of elements currently allocated for pubname_table. */ -static unsigned pubname_table_allocated; - -/* Number of elements in pubname_table currently in use. */ -static unsigned pubname_table_in_use; - -/* Size (in elements) of increments by which we may expand the - pubname_table. */ -#define PUBNAME_TABLE_INCREMENT 64 - -/* A pointer to the base of a table that contains a list of publicly - accessible names. */ -static arange_ref arange_table; - -/* Number of elements currently allocated for arange_table. */ -static unsigned arange_table_allocated; - -/* Number of elements in arange_table currently in use. */ -static unsigned arange_table_in_use; - -/* Size (in elements) of increments by which we may expand the - arange_table. */ -#define ARANGE_TABLE_INCREMENT 64 - -/* A pointer to the base of a list of pending types which we haven't - generated DIEs for yet, but which we will have to come back to - later on. */ - -static tree *pending_types_list; - -/* Number of elements currently allocated for the pending_types_list. */ -static unsigned pending_types_allocated; - -/* Number of elements of pending_types_list currently in use. */ -static unsigned pending_types; - -/* Size (in elements) of increments by which we may expand the pending - types list. Actually, a single hunk of space of this size should - be enough for most typical programs. */ -#define PENDING_TYPES_INCREMENT 64 - -/* A pointer to the base of a list of incomplete types which might be - completed at some later time. */ - -static tree *incomplete_types_list; - -/* Number of elements currently allocated for the incomplete_types_list. */ -static unsigned incomplete_types_allocated; - -/* Number of elements of incomplete_types_list currently in use. */ -static unsigned incomplete_types; - -/* Size (in elements) of increments by which we may expand the incomplete - types list. Actually, a single hunk of space of this size should - be enough for most typical programs. */ -#define INCOMPLETE_TYPES_INCREMENT 64 - -/* Record whether the function being analyzed contains inlined functions. */ -static int current_function_has_inlines; -#if 0 && defined (MIPS_DEBUGGING_INFO) -static int comp_unit_has_inlines; -#endif - -/* A pointer to the ..._DECL node which we have most recently been working - on. We keep this around just in case something about it looks screwy and - we want to tell the user what the source coordinates for the actual - declaration are. */ -static tree dwarf_last_decl; - -/* Forward declarations for functions defined in this file. */ - -static void addr_const_to_string PROTO((dyn_string_t, rtx)); -static char *addr_to_string PROTO((rtx)); -static int is_pseudo_reg PROTO((rtx)); -static tree type_main_variant PROTO((tree)); -static int is_tagged_type PROTO((tree)); -static char *dwarf_tag_name PROTO((unsigned)); -static char *dwarf_attr_name PROTO((unsigned)); -static char *dwarf_form_name PROTO((unsigned)); -static char *dwarf_stack_op_name PROTO((unsigned)); -#if 0 -static char *dwarf_type_encoding_name PROTO((unsigned)); -#endif -static tree decl_ultimate_origin PROTO((tree)); -static tree block_ultimate_origin PROTO((tree)); -static tree decl_class_context PROTO((tree)); -static void add_dwarf_attr PROTO((dw_die_ref, dw_attr_ref)); -static void add_AT_flag PROTO((dw_die_ref, - enum dwarf_attribute, - unsigned)); -static void add_AT_int PROTO((dw_die_ref, - enum dwarf_attribute, long)); -static void add_AT_unsigned PROTO((dw_die_ref, - enum dwarf_attribute, - unsigned long)); -static void add_AT_long_long PROTO((dw_die_ref, - enum dwarf_attribute, - unsigned long, unsigned long)); -static void add_AT_float PROTO((dw_die_ref, - enum dwarf_attribute, - unsigned, long *)); -static void add_AT_string PROTO((dw_die_ref, - enum dwarf_attribute, char *)); -static void add_AT_die_ref PROTO((dw_die_ref, - enum dwarf_attribute, - dw_die_ref)); -static void add_AT_fde_ref PROTO((dw_die_ref, - enum dwarf_attribute, - unsigned)); -static void add_AT_loc PROTO((dw_die_ref, - enum dwarf_attribute, - dw_loc_descr_ref)); -static void add_AT_addr PROTO((dw_die_ref, - enum dwarf_attribute, char *)); -static void add_AT_lbl_id PROTO((dw_die_ref, - enum dwarf_attribute, char *)); -static void add_AT_lbl_offset PROTO((dw_die_ref, - enum dwarf_attribute, char *)); -static int is_extern_subr_die PROTO((dw_die_ref)); -static dw_attr_ref get_AT PROTO((dw_die_ref, - enum dwarf_attribute)); -static char *get_AT_low_pc PROTO((dw_die_ref)); -static char *get_AT_hi_pc PROTO((dw_die_ref)); -static char *get_AT_string PROTO((dw_die_ref, - enum dwarf_attribute)); -static int get_AT_flag PROTO((dw_die_ref, - enum dwarf_attribute)); -static unsigned get_AT_unsigned PROTO((dw_die_ref, - enum dwarf_attribute)); -static int is_c_family PROTO((void)); -static int is_fortran PROTO((void)); -static void remove_AT PROTO((dw_die_ref, - enum dwarf_attribute)); -static void remove_children PROTO((dw_die_ref)); -static void add_child_die PROTO((dw_die_ref, dw_die_ref)); -static dw_die_ref new_die PROTO((enum dwarf_tag, dw_die_ref)); -static dw_die_ref lookup_type_die PROTO((tree)); -static void equate_type_number_to_die PROTO((tree, dw_die_ref)); -static dw_die_ref lookup_decl_die PROTO((tree)); -static void equate_decl_number_to_die PROTO((tree, dw_die_ref)); -static dw_loc_descr_ref new_loc_descr PROTO((enum dwarf_location_atom, - unsigned long, unsigned long)); -static void add_loc_descr PROTO((dw_loc_descr_ref *, - dw_loc_descr_ref)); -static void print_spaces PROTO((FILE *)); -static void print_die PROTO((dw_die_ref, FILE *)); -static void print_dwarf_line_table PROTO((FILE *)); -static void add_sibling_attributes PROTO((dw_die_ref)); -static void build_abbrev_table PROTO((dw_die_ref)); -static unsigned long size_of_string PROTO((char *)); -static unsigned long size_of_loc_descr PROTO((dw_loc_descr_ref)); -static unsigned long size_of_locs PROTO((dw_loc_descr_ref)); -static int constant_size PROTO((long unsigned)); -static unsigned long size_of_die PROTO((dw_die_ref)); -static void calc_die_sizes PROTO((dw_die_ref)); -static unsigned long size_of_line_prolog PROTO((void)); -static unsigned long size_of_line_info PROTO((void)); -static unsigned long size_of_pubnames PROTO((void)); -static unsigned long size_of_aranges PROTO((void)); -static enum dwarf_form value_format PROTO((dw_val_ref)); -static void output_value_format PROTO((dw_val_ref)); -static void output_abbrev_section PROTO((void)); -static void output_loc_operands PROTO((dw_loc_descr_ref)); -static unsigned long sibling_offset PROTO((dw_die_ref)); -static void output_die PROTO((dw_die_ref)); -static void output_compilation_unit_header PROTO((void)); -static char *dwarf2_name PROTO((tree, int)); -static void add_pubname PROTO((tree, dw_die_ref)); -static void output_pubnames PROTO((void)); -static void add_arange PROTO((tree, dw_die_ref)); -static void output_aranges PROTO((void)); -static void output_line_info PROTO((void)); -static int is_body_block PROTO((tree)); -static dw_die_ref base_type_die PROTO((tree)); -static tree root_type PROTO((tree)); -static int is_base_type PROTO((tree)); -static dw_die_ref modified_type_die PROTO((tree, int, int, dw_die_ref)); -static int type_is_enum PROTO((tree)); -static dw_loc_descr_ref reg_loc_descriptor PROTO((rtx)); -static dw_loc_descr_ref based_loc_descr PROTO((unsigned, long)); -static int is_based_loc PROTO((rtx)); -static dw_loc_descr_ref mem_loc_descriptor PROTO((rtx)); -static dw_loc_descr_ref concat_loc_descriptor PROTO((rtx, rtx)); -static dw_loc_descr_ref loc_descriptor PROTO((rtx)); -static unsigned ceiling PROTO((unsigned, unsigned)); -static tree field_type PROTO((tree)); -static unsigned simple_type_align_in_bits PROTO((tree)); -static unsigned simple_type_size_in_bits PROTO((tree)); -static unsigned field_byte_offset PROTO((tree)); -static void add_AT_location_description PROTO((dw_die_ref, - enum dwarf_attribute, rtx)); -static void add_data_member_location_attribute PROTO((dw_die_ref, tree)); -static void add_const_value_attribute PROTO((dw_die_ref, rtx)); -static void add_location_or_const_value_attribute PROTO((dw_die_ref, tree)); -static void add_name_attribute PROTO((dw_die_ref, char *)); -static void add_bound_info PROTO((dw_die_ref, - enum dwarf_attribute, tree)); -static void add_subscript_info PROTO((dw_die_ref, tree)); -static void add_byte_size_attribute PROTO((dw_die_ref, tree)); -static void add_bit_offset_attribute PROTO((dw_die_ref, tree)); -static void add_bit_size_attribute PROTO((dw_die_ref, tree)); -static void add_prototyped_attribute PROTO((dw_die_ref, tree)); -static void add_abstract_origin_attribute PROTO((dw_die_ref, tree)); -static void add_pure_or_virtual_attribute PROTO((dw_die_ref, tree)); -static void add_src_coords_attributes PROTO((dw_die_ref, tree)); -static void add_name_and_src_coords_attributes PROTO((dw_die_ref, tree)); -static void push_decl_scope PROTO((tree)); -static dw_die_ref scope_die_for PROTO((tree, dw_die_ref)); -static void pop_decl_scope PROTO((void)); -static void add_type_attribute PROTO((dw_die_ref, tree, int, int, - dw_die_ref)); -static char *type_tag PROTO((tree)); -static tree member_declared_type PROTO((tree)); -#if 0 -static char *decl_start_label PROTO((tree)); -#endif -static void gen_array_type_die PROTO((tree, dw_die_ref)); -static void gen_set_type_die PROTO((tree, dw_die_ref)); -#if 0 -static void gen_entry_point_die PROTO((tree, dw_die_ref)); -#endif -static void pend_type PROTO((tree)); -static void output_pending_types_for_scope PROTO((dw_die_ref)); -static void gen_inlined_enumeration_type_die PROTO((tree, dw_die_ref)); -static void gen_inlined_structure_type_die PROTO((tree, dw_die_ref)); -static void gen_inlined_union_type_die PROTO((tree, dw_die_ref)); -static void gen_enumeration_type_die PROTO((tree, dw_die_ref)); -static dw_die_ref gen_formal_parameter_die PROTO((tree, dw_die_ref)); -static void gen_unspecified_parameters_die PROTO((tree, dw_die_ref)); -static void gen_formal_types_die PROTO((tree, dw_die_ref)); -static void gen_subprogram_die PROTO((tree, dw_die_ref)); -static void gen_variable_die PROTO((tree, dw_die_ref)); -static void gen_label_die PROTO((tree, dw_die_ref)); -static void gen_lexical_block_die PROTO((tree, dw_die_ref, int)); -static void gen_inlined_subroutine_die PROTO((tree, dw_die_ref, int)); -static void gen_field_die PROTO((tree, dw_die_ref)); -static void gen_ptr_to_mbr_type_die PROTO((tree, dw_die_ref)); -static void gen_compile_unit_die PROTO((char *)); -static void gen_string_type_die PROTO((tree, dw_die_ref)); -static void gen_inheritance_die PROTO((tree, dw_die_ref)); -static void gen_member_die PROTO((tree, dw_die_ref)); -static void gen_struct_or_union_type_die PROTO((tree, dw_die_ref)); -static void gen_subroutine_type_die PROTO((tree, dw_die_ref)); -static void gen_typedef_die PROTO((tree, dw_die_ref)); -static void gen_type_die PROTO((tree, dw_die_ref)); -static void gen_tagged_type_instantiation_die PROTO((tree, dw_die_ref)); -static void gen_block_die PROTO((tree, dw_die_ref, int)); -static void decls_for_scope PROTO((tree, dw_die_ref, int)); -static int is_redundant_typedef PROTO((tree)); -static void gen_decl_die PROTO((tree, dw_die_ref)); -static unsigned lookup_filename PROTO((char *)); - -/* Section names used to hold DWARF debugging information. */ -#ifndef DEBUG_INFO_SECTION -#define DEBUG_INFO_SECTION ".debug_info" -#endif -#ifndef ABBREV_SECTION -#define ABBREV_SECTION ".debug_abbrev" -#endif -#ifndef ARANGES_SECTION -#define ARANGES_SECTION ".debug_aranges" -#endif -#ifndef DW_MACINFO_SECTION -#define DW_MACINFO_SECTION ".debug_macinfo" -#endif -#ifndef DEBUG_LINE_SECTION -#define DEBUG_LINE_SECTION ".debug_line" -#endif -#ifndef LOC_SECTION -#define LOC_SECTION ".debug_loc" -#endif -#ifndef PUBNAMES_SECTION -#define PUBNAMES_SECTION ".debug_pubnames" -#endif -#ifndef STR_SECTION -#define STR_SECTION ".debug_str" -#endif - -/* Standard ELF section names for compiled code and data. */ -#ifndef TEXT_SECTION -#define TEXT_SECTION ".text" -#endif -#ifndef DATA_SECTION -#define DATA_SECTION ".data" -#endif -#ifndef BSS_SECTION -#define BSS_SECTION ".bss" -#endif - -/* Labels we insert at beginning sections we can reference instead of - the section names themselves. */ - -#ifndef TEXT_SECTION_LABEL -#define TEXT_SECTION_LABEL "Ltext" -#endif -#ifndef DEBUG_LINE_SECTION_LABEL -#define DEBUG_LINE_SECTION_LABEL "Ldebug_line" -#endif -#ifndef DEBUG_INFO_SECTION_LABEL -#define DEBUG_INFO_SECTION_LABEL "Ldebug_info" -#endif -#ifndef ABBREV_SECTION_LABEL -#define ABBREV_SECTION_LABEL "Ldebug_abbrev" -#endif - - -/* Definitions of defaults for formats and names of various special - (artificial) labels which may be generated within this file (when the -g - options is used and DWARF_DEBUGGING_INFO is in effect. - If necessary, these may be overridden from within the tm.h file, but - typically, overriding these defaults is unnecessary. */ - -static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES]; -static char text_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; -static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; -static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; -static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES]; - -#ifndef TEXT_END_LABEL -#define TEXT_END_LABEL "Letext" -#endif -#ifndef DATA_END_LABEL -#define DATA_END_LABEL "Ledata" -#endif -#ifndef BSS_END_LABEL -#define BSS_END_LABEL "Lebss" -#endif -#ifndef INSN_LABEL_FMT -#define INSN_LABEL_FMT "LI%u_" -#endif -#ifndef BLOCK_BEGIN_LABEL -#define BLOCK_BEGIN_LABEL "LBB" -#endif -#ifndef BLOCK_END_LABEL -#define BLOCK_END_LABEL "LBE" -#endif -#ifndef BODY_BEGIN_LABEL -#define BODY_BEGIN_LABEL "Lbb" -#endif -#ifndef BODY_END_LABEL -#define BODY_END_LABEL "Lbe" -#endif -#ifndef LINE_CODE_LABEL -#define LINE_CODE_LABEL "LM" -#endif -#ifndef SEPARATE_LINE_CODE_LABEL -#define SEPARATE_LINE_CODE_LABEL "LSM" -#endif - -/* Convert a reference to the assembler name of a C-level name. This - macro has the same effect as ASM_OUTPUT_LABELREF, but copies to - a string rather than writing to a file. */ -#ifndef ASM_NAME_TO_STRING -#define ASM_NAME_TO_STRING(STR, NAME) \ - do { \ - if ((NAME)[0] == '*') \ - dyn_string_append (STR, NAME + 1); \ - else \ - { \ - char *newstr; \ - STRIP_NAME_ENCODING (newstr, NAME); \ - dyn_string_append (STR, user_label_prefix); \ - dyn_string_append (STR, newstr); \ - } \ - } \ - while (0) -#endif - -/* Convert an integer constant expression into assembler syntax. Addition - and subtraction are the only arithmetic that may appear in these - expressions. This is an adaptation of output_addr_const in final.c. - Here, the target of the conversion is a string buffer. We can't use - output_addr_const directly, because it writes to a file. */ - -static void -addr_const_to_string (str, x) - dyn_string_t str; - rtx x; -{ - char buf1[256]; - -restart: - switch (GET_CODE (x)) - { - case PC: - if (flag_pic) - dyn_string_append (str, ","); - else - abort (); - break; - - case SYMBOL_REF: - ASM_NAME_TO_STRING (str, XSTR (x, 0)); - break; - - case LABEL_REF: - ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); - ASM_NAME_TO_STRING (str, buf1); - break; - - case CODE_LABEL: - ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (x)); - ASM_NAME_TO_STRING (str, buf1); - break; - - case CONST_INT: - sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); - dyn_string_append (str, buf1); - break; - - case CONST: - /* This used to output parentheses around the expression, but that does - not work on the 386 (either ATT or BSD assembler). */ - addr_const_to_string (str, XEXP (x, 0)); - break; - - case CONST_DOUBLE: - if (GET_MODE (x) == VOIDmode) - { - /* We can use %d if the number is one word and positive. */ - if (CONST_DOUBLE_HIGH (x)) - sprintf (buf1, HOST_WIDE_INT_PRINT_DOUBLE_HEX, - CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); - else if (CONST_DOUBLE_LOW (x) < 0) - sprintf (buf1, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x)); - else - sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, - CONST_DOUBLE_LOW (x)); - dyn_string_append (str, buf1); - } - else - /* We can't handle floating point constants; PRINT_OPERAND must - handle them. */ - output_operand_lossage ("floating constant misused"); - break; - - case PLUS: - /* Some assemblers need integer constants to appear last (eg masm). */ - if (GET_CODE (XEXP (x, 0)) == CONST_INT) - { - addr_const_to_string (str, XEXP (x, 1)); - if (INTVAL (XEXP (x, 0)) >= 0) - dyn_string_append (str, "+"); - - addr_const_to_string (str, XEXP (x, 0)); - } - else - { - addr_const_to_string (str, XEXP (x, 0)); - if (INTVAL (XEXP (x, 1)) >= 0) - dyn_string_append (str, "+"); - - addr_const_to_string (str, XEXP (x, 1)); - } - break; - - case MINUS: - /* Avoid outputting things like x-x or x+5-x, since some assemblers - can't handle that. */ - x = simplify_subtraction (x); - if (GET_CODE (x) != MINUS) - goto restart; - - addr_const_to_string (str, XEXP (x, 0)); - dyn_string_append (str, "-"); - if (GET_CODE (XEXP (x, 1)) == CONST_INT - && INTVAL (XEXP (x, 1)) < 0) - { - dyn_string_append (str, ASM_OPEN_PAREN); - addr_const_to_string (str, XEXP (x, 1)); - dyn_string_append (str, ASM_CLOSE_PAREN); - } - else - addr_const_to_string (str, XEXP (x, 1)); - break; - - case ZERO_EXTEND: - case SIGN_EXTEND: - addr_const_to_string (str, XEXP (x, 0)); - break; - - default: - output_operand_lossage ("invalid expression as operand"); - } -} - -/* Convert an address constant to a string, and return a pointer to - a copy of the result, located on the heap. */ - -static char * -addr_to_string (x) - rtx x; -{ - dyn_string_t ds = dyn_string_new (256); - char *s; - - addr_const_to_string (ds, x); - - /* Return the dynamically allocated string, but free the - dyn_string_t itself. */ - s = ds->s; - free (ds); - return s; -} - -/* Test if rtl node points to a pseudo register. */ - -static inline int -is_pseudo_reg (rtl) - register rtx rtl; -{ - return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)) - || ((GET_CODE (rtl) == SUBREG) - && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER))); -} - -/* Return a reference to a type, with its const and volatile qualifiers - removed. */ - -static inline tree -type_main_variant (type) - register tree type; -{ - type = TYPE_MAIN_VARIANT (type); - - /* There really should be only one main variant among any group of variants - of a given type (and all of the MAIN_VARIANT values for all members of - the group should point to that one type) but sometimes the C front-end - messes this up for array types, so we work around that bug here. */ - - if (TREE_CODE (type) == ARRAY_TYPE) - while (type != TYPE_MAIN_VARIANT (type)) - type = TYPE_MAIN_VARIANT (type); - - return type; -} - -/* Return non-zero if the given type node represents a tagged type. */ - -static inline int -is_tagged_type (type) - register tree type; -{ - register enum tree_code code = TREE_CODE (type); - - return (code == RECORD_TYPE || code == UNION_TYPE - || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE); -} - -/* Convert a DIE tag into its string name. */ - -static char * -dwarf_tag_name (tag) - register unsigned tag; -{ - switch (tag) - { - case DW_TAG_padding: - return "DW_TAG_padding"; - case DW_TAG_array_type: - return "DW_TAG_array_type"; - case DW_TAG_class_type: - return "DW_TAG_class_type"; - case DW_TAG_entry_point: - return "DW_TAG_entry_point"; - case DW_TAG_enumeration_type: - return "DW_TAG_enumeration_type"; - case DW_TAG_formal_parameter: - return "DW_TAG_formal_parameter"; - case DW_TAG_imported_declaration: - return "DW_TAG_imported_declaration"; - case DW_TAG_label: - return "DW_TAG_label"; - case DW_TAG_lexical_block: - return "DW_TAG_lexical_block"; - case DW_TAG_member: - return "DW_TAG_member"; - case DW_TAG_pointer_type: - return "DW_TAG_pointer_type"; - case DW_TAG_reference_type: - return "DW_TAG_reference_type"; - case DW_TAG_compile_unit: - return "DW_TAG_compile_unit"; - case DW_TAG_string_type: - return "DW_TAG_string_type"; - case DW_TAG_structure_type: - return "DW_TAG_structure_type"; - case DW_TAG_subroutine_type: - return "DW_TAG_subroutine_type"; - case DW_TAG_typedef: - return "DW_TAG_typedef"; - case DW_TAG_union_type: - return "DW_TAG_union_type"; - case DW_TAG_unspecified_parameters: - return "DW_TAG_unspecified_parameters"; - case DW_TAG_variant: - return "DW_TAG_variant"; - case DW_TAG_common_block: - return "DW_TAG_common_block"; - case DW_TAG_common_inclusion: - return "DW_TAG_common_inclusion"; - case DW_TAG_inheritance: - return "DW_TAG_inheritance"; - case DW_TAG_inlined_subroutine: - return "DW_TAG_inlined_subroutine"; - case DW_TAG_module: - return "DW_TAG_module"; - case DW_TAG_ptr_to_member_type: - return "DW_TAG_ptr_to_member_type"; - case DW_TAG_set_type: - return "DW_TAG_set_type"; - case DW_TAG_subrange_type: - return "DW_TAG_subrange_type"; - case DW_TAG_with_stmt: - return "DW_TAG_with_stmt"; - case DW_TAG_access_declaration: - return "DW_TAG_access_declaration"; - case DW_TAG_base_type: - return "DW_TAG_base_type"; - case DW_TAG_catch_block: - return "DW_TAG_catch_block"; - case DW_TAG_const_type: - return "DW_TAG_const_type"; - case DW_TAG_constant: - return "DW_TAG_constant"; - case DW_TAG_enumerator: - return "DW_TAG_enumerator"; - case DW_TAG_file_type: - return "DW_TAG_file_type"; - case DW_TAG_friend: - return "DW_TAG_friend"; - case DW_TAG_namelist: - return "DW_TAG_namelist"; - case DW_TAG_namelist_item: - return "DW_TAG_namelist_item"; - case DW_TAG_packed_type: - return "DW_TAG_packed_type"; - case DW_TAG_subprogram: - return "DW_TAG_subprogram"; - case DW_TAG_template_type_param: - return "DW_TAG_template_type_param"; - case DW_TAG_template_value_param: - return "DW_TAG_template_value_param"; - case DW_TAG_thrown_type: - return "DW_TAG_thrown_type"; - case DW_TAG_try_block: - return "DW_TAG_try_block"; - case DW_TAG_variant_part: - return "DW_TAG_variant_part"; - case DW_TAG_variable: - return "DW_TAG_variable"; - case DW_TAG_volatile_type: - return "DW_TAG_volatile_type"; - case DW_TAG_MIPS_loop: - return "DW_TAG_MIPS_loop"; - case DW_TAG_format_label: - return "DW_TAG_format_label"; - case DW_TAG_function_template: - return "DW_TAG_function_template"; - case DW_TAG_class_template: - return "DW_TAG_class_template"; - default: - return "DW_TAG_<unknown>"; - } -} - -/* Convert a DWARF attribute code into its string name. */ - -static char * -dwarf_attr_name (attr) - register unsigned attr; -{ - switch (attr) - { - case DW_AT_sibling: - return "DW_AT_sibling"; - case DW_AT_location: - return "DW_AT_location"; - case DW_AT_name: - return "DW_AT_name"; - case DW_AT_ordering: - return "DW_AT_ordering"; - case DW_AT_subscr_data: - return "DW_AT_subscr_data"; - case DW_AT_byte_size: - return "DW_AT_byte_size"; - case DW_AT_bit_offset: - return "DW_AT_bit_offset"; - case DW_AT_bit_size: - return "DW_AT_bit_size"; - case DW_AT_element_list: - return "DW_AT_element_list"; - case DW_AT_stmt_list: - return "DW_AT_stmt_list"; - case DW_AT_low_pc: - return "DW_AT_low_pc"; - case DW_AT_high_pc: - return "DW_AT_high_pc"; - case DW_AT_language: - return "DW_AT_language"; - case DW_AT_member: - return "DW_AT_member"; - case DW_AT_discr: - return "DW_AT_discr"; - case DW_AT_discr_value: - return "DW_AT_discr_value"; - case DW_AT_visibility: - return "DW_AT_visibility"; - case DW_AT_import: - return "DW_AT_import"; - case DW_AT_string_length: - return "DW_AT_string_length"; - case DW_AT_common_reference: - return "DW_AT_common_reference"; - case DW_AT_comp_dir: - return "DW_AT_comp_dir"; - case DW_AT_const_value: - return "DW_AT_const_value"; - case DW_AT_containing_type: - return "DW_AT_containing_type"; - case DW_AT_default_value: - return "DW_AT_default_value"; - case DW_AT_inline: - return "DW_AT_inline"; - case DW_AT_is_optional: - return "DW_AT_is_optional"; - case DW_AT_lower_bound: - return "DW_AT_lower_bound"; - case DW_AT_producer: - return "DW_AT_producer"; - case DW_AT_prototyped: - return "DW_AT_prototyped"; - case DW_AT_return_addr: - return "DW_AT_return_addr"; - case DW_AT_start_scope: - return "DW_AT_start_scope"; - case DW_AT_stride_size: - return "DW_AT_stride_size"; - case DW_AT_upper_bound: - return "DW_AT_upper_bound"; - case DW_AT_abstract_origin: - return "DW_AT_abstract_origin"; - case DW_AT_accessibility: - return "DW_AT_accessibility"; - case DW_AT_address_class: - return "DW_AT_address_class"; - case DW_AT_artificial: - return "DW_AT_artificial"; - case DW_AT_base_types: - return "DW_AT_base_types"; - case DW_AT_calling_convention: - return "DW_AT_calling_convention"; - case DW_AT_count: - return "DW_AT_count"; - case DW_AT_data_member_location: - return "DW_AT_data_member_location"; - case DW_AT_decl_column: - return "DW_AT_decl_column"; - case DW_AT_decl_file: - return "DW_AT_decl_file"; - case DW_AT_decl_line: - return "DW_AT_decl_line"; - case DW_AT_declaration: - return "DW_AT_declaration"; - case DW_AT_discr_list: - return "DW_AT_discr_list"; - case DW_AT_encoding: - return "DW_AT_encoding"; - case DW_AT_external: - return "DW_AT_external"; - case DW_AT_frame_base: - return "DW_AT_frame_base"; - case DW_AT_friend: - return "DW_AT_friend"; - case DW_AT_identifier_case: - return "DW_AT_identifier_case"; - case DW_AT_macro_info: - return "DW_AT_macro_info"; - case DW_AT_namelist_items: - return "DW_AT_namelist_items"; - case DW_AT_priority: - return "DW_AT_priority"; - case DW_AT_segment: - return "DW_AT_segment"; - case DW_AT_specification: - return "DW_AT_specification"; - case DW_AT_static_link: - return "DW_AT_static_link"; - case DW_AT_type: - return "DW_AT_type"; - case DW_AT_use_location: - return "DW_AT_use_location"; - case DW_AT_variable_parameter: - return "DW_AT_variable_parameter"; - case DW_AT_virtuality: - return "DW_AT_virtuality"; - case DW_AT_vtable_elem_location: - return "DW_AT_vtable_elem_location"; - - case DW_AT_MIPS_fde: - return "DW_AT_MIPS_fde"; - case DW_AT_MIPS_loop_begin: - return "DW_AT_MIPS_loop_begin"; - case DW_AT_MIPS_tail_loop_begin: - return "DW_AT_MIPS_tail_loop_begin"; - case DW_AT_MIPS_epilog_begin: - return "DW_AT_MIPS_epilog_begin"; - case DW_AT_MIPS_loop_unroll_factor: - return "DW_AT_MIPS_loop_unroll_factor"; - case DW_AT_MIPS_software_pipeline_depth: - return "DW_AT_MIPS_software_pipeline_depth"; - case DW_AT_MIPS_linkage_name: - return "DW_AT_MIPS_linkage_name"; - case DW_AT_MIPS_stride: - return "DW_AT_MIPS_stride"; - case DW_AT_MIPS_abstract_name: - return "DW_AT_MIPS_abstract_name"; - case DW_AT_MIPS_clone_origin: - return "DW_AT_MIPS_clone_origin"; - case DW_AT_MIPS_has_inlines: - return "DW_AT_MIPS_has_inlines"; - - case DW_AT_sf_names: - return "DW_AT_sf_names"; - case DW_AT_src_info: - return "DW_AT_src_info"; - case DW_AT_mac_info: - return "DW_AT_mac_info"; - case DW_AT_src_coords: - return "DW_AT_src_coords"; - case DW_AT_body_begin: - return "DW_AT_body_begin"; - case DW_AT_body_end: - return "DW_AT_body_end"; - default: - return "DW_AT_<unknown>"; - } -} - -/* Convert a DWARF value form code into its string name. */ - -static char * -dwarf_form_name (form) - register unsigned form; -{ - switch (form) - { - case DW_FORM_addr: - return "DW_FORM_addr"; - case DW_FORM_block2: - return "DW_FORM_block2"; - case DW_FORM_block4: - return "DW_FORM_block4"; - case DW_FORM_data2: - return "DW_FORM_data2"; - case DW_FORM_data4: - return "DW_FORM_data4"; - case DW_FORM_data8: - return "DW_FORM_data8"; - case DW_FORM_string: - return "DW_FORM_string"; - case DW_FORM_block: - return "DW_FORM_block"; - case DW_FORM_block1: - return "DW_FORM_block1"; - case DW_FORM_data1: - return "DW_FORM_data1"; - case DW_FORM_flag: - return "DW_FORM_flag"; - case DW_FORM_sdata: - return "DW_FORM_sdata"; - case DW_FORM_strp: - return "DW_FORM_strp"; - case DW_FORM_udata: - return "DW_FORM_udata"; - case DW_FORM_ref_addr: - return "DW_FORM_ref_addr"; - case DW_FORM_ref1: - return "DW_FORM_ref1"; - case DW_FORM_ref2: - return "DW_FORM_ref2"; - case DW_FORM_ref4: - return "DW_FORM_ref4"; - case DW_FORM_ref8: - return "DW_FORM_ref8"; - case DW_FORM_ref_udata: - return "DW_FORM_ref_udata"; - case DW_FORM_indirect: - return "DW_FORM_indirect"; - default: - return "DW_FORM_<unknown>"; - } -} - -/* Convert a DWARF stack opcode into its string name. */ - -static char * -dwarf_stack_op_name (op) - register unsigned op; -{ - switch (op) - { - case DW_OP_addr: - return "DW_OP_addr"; - case DW_OP_deref: - return "DW_OP_deref"; - case DW_OP_const1u: - return "DW_OP_const1u"; - case DW_OP_const1s: - return "DW_OP_const1s"; - case DW_OP_const2u: - return "DW_OP_const2u"; - case DW_OP_const2s: - return "DW_OP_const2s"; - case DW_OP_const4u: - return "DW_OP_const4u"; - case DW_OP_const4s: - return "DW_OP_const4s"; - case DW_OP_const8u: - return "DW_OP_const8u"; - case DW_OP_const8s: - return "DW_OP_const8s"; - case DW_OP_constu: - return "DW_OP_constu"; - case DW_OP_consts: - return "DW_OP_consts"; - case DW_OP_dup: - return "DW_OP_dup"; - case DW_OP_drop: - return "DW_OP_drop"; - case DW_OP_over: - return "DW_OP_over"; - case DW_OP_pick: - return "DW_OP_pick"; - case DW_OP_swap: - return "DW_OP_swap"; - case DW_OP_rot: - return "DW_OP_rot"; - case DW_OP_xderef: - return "DW_OP_xderef"; - case DW_OP_abs: - return "DW_OP_abs"; - case DW_OP_and: - return "DW_OP_and"; - case DW_OP_div: - return "DW_OP_div"; - case DW_OP_minus: - return "DW_OP_minus"; - case DW_OP_mod: - return "DW_OP_mod"; - case DW_OP_mul: - return "DW_OP_mul"; - case DW_OP_neg: - return "DW_OP_neg"; - case DW_OP_not: - return "DW_OP_not"; - case DW_OP_or: - return "DW_OP_or"; - case DW_OP_plus: - return "DW_OP_plus"; - case DW_OP_plus_uconst: - return "DW_OP_plus_uconst"; - case DW_OP_shl: - return "DW_OP_shl"; - case DW_OP_shr: - return "DW_OP_shr"; - case DW_OP_shra: - return "DW_OP_shra"; - case DW_OP_xor: - return "DW_OP_xor"; - case DW_OP_bra: - return "DW_OP_bra"; - case DW_OP_eq: - return "DW_OP_eq"; - case DW_OP_ge: - return "DW_OP_ge"; - case DW_OP_gt: - return "DW_OP_gt"; - case DW_OP_le: - return "DW_OP_le"; - case DW_OP_lt: - return "DW_OP_lt"; - case DW_OP_ne: - return "DW_OP_ne"; - case DW_OP_skip: - return "DW_OP_skip"; - case DW_OP_lit0: - return "DW_OP_lit0"; - case DW_OP_lit1: - return "DW_OP_lit1"; - case DW_OP_lit2: - return "DW_OP_lit2"; - case DW_OP_lit3: - return "DW_OP_lit3"; - case DW_OP_lit4: - return "DW_OP_lit4"; - case DW_OP_lit5: - return "DW_OP_lit5"; - case DW_OP_lit6: - return "DW_OP_lit6"; - case DW_OP_lit7: - return "DW_OP_lit7"; - case DW_OP_lit8: - return "DW_OP_lit8"; - case DW_OP_lit9: - return "DW_OP_lit9"; - case DW_OP_lit10: - return "DW_OP_lit10"; - case DW_OP_lit11: - return "DW_OP_lit11"; - case DW_OP_lit12: - return "DW_OP_lit12"; - case DW_OP_lit13: - return "DW_OP_lit13"; - case DW_OP_lit14: - return "DW_OP_lit14"; - case DW_OP_lit15: - return "DW_OP_lit15"; - case DW_OP_lit16: - return "DW_OP_lit16"; - case DW_OP_lit17: - return "DW_OP_lit17"; - case DW_OP_lit18: - return "DW_OP_lit18"; - case DW_OP_lit19: - return "DW_OP_lit19"; - case DW_OP_lit20: - return "DW_OP_lit20"; - case DW_OP_lit21: - return "DW_OP_lit21"; - case DW_OP_lit22: - return "DW_OP_lit22"; - case DW_OP_lit23: - return "DW_OP_lit23"; - case DW_OP_lit24: - return "DW_OP_lit24"; - case DW_OP_lit25: - return "DW_OP_lit25"; - case DW_OP_lit26: - return "DW_OP_lit26"; - case DW_OP_lit27: - return "DW_OP_lit27"; - case DW_OP_lit28: - return "DW_OP_lit28"; - case DW_OP_lit29: - return "DW_OP_lit29"; - case DW_OP_lit30: - return "DW_OP_lit30"; - case DW_OP_lit31: - return "DW_OP_lit31"; - case DW_OP_reg0: - return "DW_OP_reg0"; - case DW_OP_reg1: - return "DW_OP_reg1"; - case DW_OP_reg2: - return "DW_OP_reg2"; - case DW_OP_reg3: - return "DW_OP_reg3"; - case DW_OP_reg4: - return "DW_OP_reg4"; - case DW_OP_reg5: - return "DW_OP_reg5"; - case DW_OP_reg6: - return "DW_OP_reg6"; - case DW_OP_reg7: - return "DW_OP_reg7"; - case DW_OP_reg8: - return "DW_OP_reg8"; - case DW_OP_reg9: - return "DW_OP_reg9"; - case DW_OP_reg10: - return "DW_OP_reg10"; - case DW_OP_reg11: - return "DW_OP_reg11"; - case DW_OP_reg12: - return "DW_OP_reg12"; - case DW_OP_reg13: - return "DW_OP_reg13"; - case DW_OP_reg14: - return "DW_OP_reg14"; - case DW_OP_reg15: - return "DW_OP_reg15"; - case DW_OP_reg16: - return "DW_OP_reg16"; - case DW_OP_reg17: - return "DW_OP_reg17"; - case DW_OP_reg18: - return "DW_OP_reg18"; - case DW_OP_reg19: - return "DW_OP_reg19"; - case DW_OP_reg20: - return "DW_OP_reg20"; - case DW_OP_reg21: - return "DW_OP_reg21"; - case DW_OP_reg22: - return "DW_OP_reg22"; - case DW_OP_reg23: - return "DW_OP_reg23"; - case DW_OP_reg24: - return "DW_OP_reg24"; - case DW_OP_reg25: - return "DW_OP_reg25"; - case DW_OP_reg26: - return "DW_OP_reg26"; - case DW_OP_reg27: - return "DW_OP_reg27"; - case DW_OP_reg28: - return "DW_OP_reg28"; - case DW_OP_reg29: - return "DW_OP_reg29"; - case DW_OP_reg30: - return "DW_OP_reg30"; - case DW_OP_reg31: - return "DW_OP_reg31"; - case DW_OP_breg0: - return "DW_OP_breg0"; - case DW_OP_breg1: - return "DW_OP_breg1"; - case DW_OP_breg2: - return "DW_OP_breg2"; - case DW_OP_breg3: - return "DW_OP_breg3"; - case DW_OP_breg4: - return "DW_OP_breg4"; - case DW_OP_breg5: - return "DW_OP_breg5"; - case DW_OP_breg6: - return "DW_OP_breg6"; - case DW_OP_breg7: - return "DW_OP_breg7"; - case DW_OP_breg8: - return "DW_OP_breg8"; - case DW_OP_breg9: - return "DW_OP_breg9"; - case DW_OP_breg10: - return "DW_OP_breg10"; - case DW_OP_breg11: - return "DW_OP_breg11"; - case DW_OP_breg12: - return "DW_OP_breg12"; - case DW_OP_breg13: - return "DW_OP_breg13"; - case DW_OP_breg14: - return "DW_OP_breg14"; - case DW_OP_breg15: - return "DW_OP_breg15"; - case DW_OP_breg16: - return "DW_OP_breg16"; - case DW_OP_breg17: - return "DW_OP_breg17"; - case DW_OP_breg18: - return "DW_OP_breg18"; - case DW_OP_breg19: - return "DW_OP_breg19"; - case DW_OP_breg20: - return "DW_OP_breg20"; - case DW_OP_breg21: - return "DW_OP_breg21"; - case DW_OP_breg22: - return "DW_OP_breg22"; - case DW_OP_breg23: - return "DW_OP_breg23"; - case DW_OP_breg24: - return "DW_OP_breg24"; - case DW_OP_breg25: - return "DW_OP_breg25"; - case DW_OP_breg26: - return "DW_OP_breg26"; - case DW_OP_breg27: - return "DW_OP_breg27"; - case DW_OP_breg28: - return "DW_OP_breg28"; - case DW_OP_breg29: - return "DW_OP_breg29"; - case DW_OP_breg30: - return "DW_OP_breg30"; - case DW_OP_breg31: - return "DW_OP_breg31"; - case DW_OP_regx: - return "DW_OP_regx"; - case DW_OP_fbreg: - return "DW_OP_fbreg"; - case DW_OP_bregx: - return "DW_OP_bregx"; - case DW_OP_piece: - return "DW_OP_piece"; - case DW_OP_deref_size: - return "DW_OP_deref_size"; - case DW_OP_xderef_size: - return "DW_OP_xderef_size"; - case DW_OP_nop: - return "DW_OP_nop"; - default: - return "OP_<unknown>"; - } -} - -/* Convert a DWARF type code into its string name. */ - -#if 0 -static char * -dwarf_type_encoding_name (enc) - register unsigned enc; -{ - switch (enc) - { - case DW_ATE_address: - return "DW_ATE_address"; - case DW_ATE_boolean: - return "DW_ATE_boolean"; - case DW_ATE_complex_float: - return "DW_ATE_complex_float"; - case DW_ATE_float: - return "DW_ATE_float"; - case DW_ATE_signed: - return "DW_ATE_signed"; - case DW_ATE_signed_char: - return "DW_ATE_signed_char"; - case DW_ATE_unsigned: - return "DW_ATE_unsigned"; - case DW_ATE_unsigned_char: - return "DW_ATE_unsigned_char"; - default: - return "DW_ATE_<unknown>"; - } -} -#endif - -/* Determine the "ultimate origin" of a decl. The decl may be an inlined - instance of an inlined instance of a decl which is local to an inline - function, so we have to trace all of the way back through the origin chain - to find out what sort of node actually served as the original seed for the - given block. */ - -static tree -decl_ultimate_origin (decl) - register tree decl; -{ -#ifdef ENABLE_CHECKING - if (DECL_FROM_INLINE (DECL_ORIGIN (decl))) - /* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the - most distant ancestor, this should never happen. */ - abort (); -#endif - - return DECL_ABSTRACT_ORIGIN (decl); -} - -/* Determine the "ultimate origin" of a block. The block may be an inlined - instance of an inlined instance of a block which is local to an inline - function, so we have to trace all of the way back through the origin chain - to find out what sort of node actually served as the original seed for the - given block. */ - -static tree -block_ultimate_origin (block) - register tree block; -{ - register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block); - - if (immediate_origin == NULL_TREE) - return NULL_TREE; - else - { - register tree ret_val; - register tree lookahead = immediate_origin; - - do - { - ret_val = lookahead; - lookahead = (TREE_CODE (ret_val) == BLOCK) - ? BLOCK_ABSTRACT_ORIGIN (ret_val) - : NULL; - } - while (lookahead != NULL && lookahead != ret_val); - - return ret_val; - } -} - -/* Get the class to which DECL belongs, if any. In g++, the DECL_CONTEXT - of a virtual function may refer to a base class, so we check the 'this' - parameter. */ - -static tree -decl_class_context (decl) - tree decl; -{ - tree context = NULL_TREE; - - if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl)) - context = DECL_CONTEXT (decl); - else - context = TYPE_MAIN_VARIANT - (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))))); - - if (context && TREE_CODE_CLASS (TREE_CODE (context)) != 't') - context = NULL_TREE; - - return context; -} - -/* Add an attribute/value pair to a DIE */ - -static inline void -add_dwarf_attr (die, attr) - register dw_die_ref die; - register dw_attr_ref attr; -{ - if (die != NULL && attr != NULL) - { - if (die->die_attr == NULL) - { - die->die_attr = attr; - die->die_attr_last = attr; - } - else - { - die->die_attr_last->dw_attr_next = attr; - die->die_attr_last = attr; - } - } -} - -/* Add a flag value attribute to a DIE. */ - -static inline void -add_AT_flag (die, attr_kind, flag) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register unsigned flag; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_flag; - attr->dw_attr_val.v.val_flag = flag; - add_dwarf_attr (die, attr); -} - -/* Add a signed integer attribute value to a DIE. */ - -static inline void -add_AT_int (die, attr_kind, int_val) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register long int int_val; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_const; - attr->dw_attr_val.v.val_int = int_val; - add_dwarf_attr (die, attr); -} - -/* Add an unsigned integer attribute value to a DIE. */ - -static inline void -add_AT_unsigned (die, attr_kind, unsigned_val) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register unsigned long unsigned_val; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_unsigned_const; - attr->dw_attr_val.v.val_unsigned = unsigned_val; - add_dwarf_attr (die, attr); -} - -/* Add an unsigned double integer attribute value to a DIE. */ - -static inline void -add_AT_long_long (die, attr_kind, val_hi, val_low) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register unsigned long val_hi; - register unsigned long val_low; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_long_long; - attr->dw_attr_val.v.val_long_long.hi = val_hi; - attr->dw_attr_val.v.val_long_long.low = val_low; - add_dwarf_attr (die, attr); -} - -/* Add a floating point attribute value to a DIE and return it. */ - -static inline void -add_AT_float (die, attr_kind, length, array) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register unsigned length; - register long *array; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_float; - attr->dw_attr_val.v.val_float.length = length; - attr->dw_attr_val.v.val_float.array = array; - add_dwarf_attr (die, attr); -} - -/* Add a string attribute value to a DIE. */ - -static inline void -add_AT_string (die, attr_kind, str) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register char *str; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_str; - attr->dw_attr_val.v.val_str = xstrdup (str); - add_dwarf_attr (die, attr); -} - -/* Add a DIE reference attribute value to a DIE. */ - -static inline void -add_AT_die_ref (die, attr_kind, targ_die) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register dw_die_ref targ_die; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_die_ref; - attr->dw_attr_val.v.val_die_ref = targ_die; - add_dwarf_attr (die, attr); -} - -/* Add an FDE reference attribute value to a DIE. */ - -static inline void -add_AT_fde_ref (die, attr_kind, targ_fde) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register unsigned targ_fde; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_fde_ref; - attr->dw_attr_val.v.val_fde_index = targ_fde; - add_dwarf_attr (die, attr); -} - -/* Add a location description attribute value to a DIE. */ - -static inline void -add_AT_loc (die, attr_kind, loc) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register dw_loc_descr_ref loc; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_loc; - attr->dw_attr_val.v.val_loc = loc; - add_dwarf_attr (die, attr); -} - -/* Add an address constant attribute value to a DIE. */ - -static inline void -add_AT_addr (die, attr_kind, addr) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - char *addr; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_addr; - attr->dw_attr_val.v.val_addr = addr; - add_dwarf_attr (die, attr); -} - -/* Add a label identifier attribute value to a DIE. */ - -static inline void -add_AT_lbl_id (die, attr_kind, lbl_id) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register char *lbl_id; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_lbl_id; - attr->dw_attr_val.v.val_lbl_id = xstrdup (lbl_id); - add_dwarf_attr (die, attr); -} - -/* Add a section offset attribute value to a DIE. */ - -static inline void -add_AT_lbl_offset (die, attr_kind, label) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; - register char *label; -{ - register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - - attr->dw_attr_next = NULL; - attr->dw_attr = attr_kind; - attr->dw_attr_val.val_class = dw_val_class_lbl_offset; - attr->dw_attr_val.v.val_lbl_id = label; - add_dwarf_attr (die, attr); - -} - -/* Test if die refers to an external subroutine. */ - -static inline int -is_extern_subr_die (die) - register dw_die_ref die; -{ - register dw_attr_ref a; - register int is_subr = FALSE; - register int is_extern = FALSE; - - if (die != NULL && die->die_tag == DW_TAG_subprogram) - { - is_subr = TRUE; - for (a = die->die_attr; a != NULL; a = a->dw_attr_next) - { - if (a->dw_attr == DW_AT_external - && a->dw_attr_val.val_class == dw_val_class_flag - && a->dw_attr_val.v.val_flag != 0) - { - is_extern = TRUE; - break; - } - } - } - - return is_subr && is_extern; -} - -/* Get the attribute of type attr_kind. */ - -static inline dw_attr_ref -get_AT (die, attr_kind) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; -{ - register dw_attr_ref a; - register dw_die_ref spec = NULL; - - if (die != NULL) - { - for (a = die->die_attr; a != NULL; a = a->dw_attr_next) - { - if (a->dw_attr == attr_kind) - return a; - - if (a->dw_attr == DW_AT_specification - || a->dw_attr == DW_AT_abstract_origin) - spec = a->dw_attr_val.v.val_die_ref; - } - - if (spec) - return get_AT (spec, attr_kind); - } - - return NULL; -} - -/* Return the "low pc" attribute value, typically associated with - a subprogram DIE. Return null if the "low pc" attribute is - either not prsent, or if it cannot be represented as an - assembler label identifier. */ - -static inline char * -get_AT_low_pc (die) - register dw_die_ref die; -{ - register dw_attr_ref a = get_AT (die, DW_AT_low_pc); - - if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id) - return a->dw_attr_val.v.val_lbl_id; - - return NULL; -} - -/* Return the "high pc" attribute value, typically associated with - a subprogram DIE. Return null if the "high pc" attribute is - either not prsent, or if it cannot be represented as an - assembler label identifier. */ - -static inline char * -get_AT_hi_pc (die) - register dw_die_ref die; -{ - register dw_attr_ref a = get_AT (die, DW_AT_high_pc); - - if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id) - return a->dw_attr_val.v.val_lbl_id; - - return NULL; -} - -/* Return the value of the string attribute designated by ATTR_KIND, or - NULL if it is not present. */ - -static inline char * -get_AT_string (die, attr_kind) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; -{ - register dw_attr_ref a = get_AT (die, attr_kind); - - if (a && a->dw_attr_val.val_class == dw_val_class_str) - return a->dw_attr_val.v.val_str; - - return NULL; -} - -/* Return the value of the flag attribute designated by ATTR_KIND, or -1 - if it is not present. */ - -static inline int -get_AT_flag (die, attr_kind) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; -{ - register dw_attr_ref a = get_AT (die, attr_kind); - - if (a && a->dw_attr_val.val_class == dw_val_class_flag) - return a->dw_attr_val.v.val_flag; - - return -1; -} - -/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0 - if it is not present. */ - -static inline unsigned -get_AT_unsigned (die, attr_kind) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; -{ - register dw_attr_ref a = get_AT (die, attr_kind); - - if (a && a->dw_attr_val.val_class == dw_val_class_unsigned_const) - return a->dw_attr_val.v.val_unsigned; - - return 0; -} - -static inline int -is_c_family () -{ - register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language); - - return (lang == DW_LANG_C || lang == DW_LANG_C89 - || lang == DW_LANG_C_plus_plus); -} - -static inline int -is_fortran () -{ - register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language); - - return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90); -} - -/* Remove the specified attribute if present. */ - -static inline void -remove_AT (die, attr_kind) - register dw_die_ref die; - register enum dwarf_attribute attr_kind; -{ - register dw_attr_ref a; - register dw_attr_ref removed = NULL;; - - if (die != NULL) - { - if (die->die_attr->dw_attr == attr_kind) - { - removed = die->die_attr; - if (die->die_attr_last == die->die_attr) - die->die_attr_last = NULL; - - die->die_attr = die->die_attr->dw_attr_next; - } - - else - for (a = die->die_attr; a->dw_attr_next != NULL; - a = a->dw_attr_next) - if (a->dw_attr_next->dw_attr == attr_kind) - { - removed = a->dw_attr_next; - if (die->die_attr_last == a->dw_attr_next) - die->die_attr_last = a; - - a->dw_attr_next = a->dw_attr_next->dw_attr_next; - break; - } - - if (removed != 0) - free (removed); - } -} - -/* Discard the children of this DIE. */ - -static inline void -remove_children (die) - register dw_die_ref die; -{ - register dw_die_ref child_die = die->die_child; - - die->die_child = NULL; - die->die_child_last = NULL; - - while (child_die != NULL) - { - register dw_die_ref tmp_die = child_die; - register dw_attr_ref a; - - child_die = child_die->die_sib; - - for (a = tmp_die->die_attr; a != NULL; ) - { - register dw_attr_ref tmp_a = a; - - a = a->dw_attr_next; - free (tmp_a); - } - - free (tmp_die); - } -} - -/* Add a child DIE below its parent. */ - -static inline void -add_child_die (die, child_die) - register dw_die_ref die; - register dw_die_ref child_die; -{ - if (die != NULL && child_die != NULL) - { - if (die == child_die) - abort (); - child_die->die_parent = die; - child_die->die_sib = NULL; - - if (die->die_child == NULL) - { - die->die_child = child_die; - die->die_child_last = child_die; - } - else - { - die->die_child_last->die_sib = child_die; - die->die_child_last = child_die; - } - } -} - -/* Return a pointer to a newly created DIE node. */ - -static inline dw_die_ref -new_die (tag_value, parent_die) - register enum dwarf_tag tag_value; - register dw_die_ref parent_die; -{ - register dw_die_ref die = (dw_die_ref) xmalloc (sizeof (die_node)); - - die->die_tag = tag_value; - die->die_abbrev = 0; - die->die_offset = 0; - die->die_child = NULL; - die->die_parent = NULL; - die->die_sib = NULL; - die->die_child_last = NULL; - die->die_attr = NULL; - die->die_attr_last = NULL; - - if (parent_die != NULL) - add_child_die (parent_die, die); - else - { - limbo_die_node *limbo_node; - - limbo_node = (limbo_die_node *) xmalloc (sizeof (limbo_die_node)); - limbo_node->die = die; - limbo_node->next = limbo_die_list; - limbo_die_list = limbo_node; - } - - return die; -} - -/* Return the DIE associated with the given type specifier. */ - -static inline dw_die_ref -lookup_type_die (type) - register tree type; -{ - return (dw_die_ref) TYPE_SYMTAB_POINTER (type); -} - -/* Equate a DIE to a given type specifier. */ - -static void -equate_type_number_to_die (type, type_die) - register tree type; - register dw_die_ref type_die; -{ - TYPE_SYMTAB_POINTER (type) = (char *) type_die; -} - -/* Return the DIE associated with a given declaration. */ - -static inline dw_die_ref -lookup_decl_die (decl) - register tree decl; -{ - register unsigned decl_id = DECL_UID (decl); - - return (decl_id < decl_die_table_in_use - ? decl_die_table[decl_id] : NULL); -} - -/* Equate a DIE to a particular declaration. */ - -static void -equate_decl_number_to_die (decl, decl_die) - register tree decl; - register dw_die_ref decl_die; -{ - register unsigned decl_id = DECL_UID (decl); - register unsigned num_allocated; - - if (decl_id >= decl_die_table_allocated) - { - num_allocated - = ((decl_id + 1 + DECL_DIE_TABLE_INCREMENT - 1) - / DECL_DIE_TABLE_INCREMENT) - * DECL_DIE_TABLE_INCREMENT; - - decl_die_table - = (dw_die_ref *) xrealloc (decl_die_table, - sizeof (dw_die_ref) * num_allocated); - - bzero ((char *) &decl_die_table[decl_die_table_allocated], - (num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref)); - decl_die_table_allocated = num_allocated; - } - - if (decl_id >= decl_die_table_in_use) - decl_die_table_in_use = (decl_id + 1); - - decl_die_table[decl_id] = decl_die; -} - -/* Return a pointer to a newly allocated location description. Location - descriptions are simple expression terms that can be strung - together to form more complicated location (address) descriptions. */ - -static inline dw_loc_descr_ref -new_loc_descr (op, oprnd1, oprnd2) - register enum dwarf_location_atom op; - register unsigned long oprnd1; - register unsigned long oprnd2; -{ - register dw_loc_descr_ref descr - = (dw_loc_descr_ref) xmalloc (sizeof (dw_loc_descr_node)); - - descr->dw_loc_next = NULL; - descr->dw_loc_opc = op; - descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const; - descr->dw_loc_oprnd1.v.val_unsigned = oprnd1; - descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const; - descr->dw_loc_oprnd2.v.val_unsigned = oprnd2; - - return descr; -} - -/* Add a location description term to a location description expression. */ - -static inline void -add_loc_descr (list_head, descr) - register dw_loc_descr_ref *list_head; - register dw_loc_descr_ref descr; -{ - register dw_loc_descr_ref *d; - - /* Find the end of the chain. */ - for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next) - ; - - *d = descr; -} - -/* Keep track of the number of spaces used to indent the - output of the debugging routines that print the structure of - the DIE internal representation. */ -static int print_indent; - -/* Indent the line the number of spaces given by print_indent. */ - -static inline void -print_spaces (outfile) - FILE *outfile; -{ - fprintf (outfile, "%*s", print_indent, ""); -} - -/* Print the information associated with a given DIE, and its children. - This routine is a debugging aid only. */ - -static void -print_die (die, outfile) - dw_die_ref die; - FILE *outfile; -{ - register dw_attr_ref a; - register dw_die_ref c; - - print_spaces (outfile); - fprintf (outfile, "DIE %4lu: %s\n", - die->die_offset, dwarf_tag_name (die->die_tag)); - print_spaces (outfile); - fprintf (outfile, " abbrev id: %lu", die->die_abbrev); - fprintf (outfile, " offset: %lu\n", die->die_offset); - - for (a = die->die_attr; a != NULL; a = a->dw_attr_next) - { - print_spaces (outfile); - fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr)); - - switch (a->dw_attr_val.val_class) - { - case dw_val_class_addr: - fprintf (outfile, "address"); - break; - case dw_val_class_loc: - fprintf (outfile, "location descriptor"); - break; - case dw_val_class_const: - fprintf (outfile, "%ld", a->dw_attr_val.v.val_int); - break; - case dw_val_class_unsigned_const: - fprintf (outfile, "%lu", a->dw_attr_val.v.val_unsigned); - break; - case dw_val_class_long_long: - fprintf (outfile, "constant (%lu,%lu)", - a->dw_attr_val.v.val_long_long.hi, - a->dw_attr_val.v.val_long_long.low); - break; - case dw_val_class_float: - fprintf (outfile, "floating-point constant"); - break; - case dw_val_class_flag: - fprintf (outfile, "%u", a->dw_attr_val.v.val_flag); - break; - case dw_val_class_die_ref: - if (a->dw_attr_val.v.val_die_ref != NULL) - fprintf (outfile, "die -> %lu", - a->dw_attr_val.v.val_die_ref->die_offset); - else - fprintf (outfile, "die -> <null>"); - break; - case dw_val_class_lbl_id: - case dw_val_class_lbl_offset: - fprintf (outfile, "label: %s", a->dw_attr_val.v.val_lbl_id); - break; - case dw_val_class_str: - if (a->dw_attr_val.v.val_str != NULL) - fprintf (outfile, "\"%s\"", a->dw_attr_val.v.val_str); - else - fprintf (outfile, "<null>"); - break; - default: - break; - } - - fprintf (outfile, "\n"); - } - - if (die->die_child != NULL) - { - print_indent += 4; - for (c = die->die_child; c != NULL; c = c->die_sib) - print_die (c, outfile); - - print_indent -= 4; - } -} - -/* Print the contents of the source code line number correspondence table. - This routine is a debugging aid only. */ - -static void -print_dwarf_line_table (outfile) - FILE *outfile; -{ - register unsigned i; - register dw_line_info_ref line_info; - - fprintf (outfile, "\n\nDWARF source line information\n"); - for (i = 1; i < line_info_table_in_use; ++i) - { - line_info = &line_info_table[i]; - fprintf (outfile, "%5d: ", i); - fprintf (outfile, "%-20s", file_table[line_info->dw_file_num]); - fprintf (outfile, "%6ld", line_info->dw_line_num); - fprintf (outfile, "\n"); - } - - fprintf (outfile, "\n\n"); -} - -/* Print the information collected for a given DIE. */ - -void -debug_dwarf_die (die) - dw_die_ref die; -{ - print_die (die, stderr); -} - -/* Print all DWARF information collected for the compilation unit. - This routine is a debugging aid only. */ - -void -debug_dwarf () -{ - print_indent = 0; - print_die (comp_unit_die, stderr); - print_dwarf_line_table (stderr); -} - -/* Traverse the DIE, and add a sibling attribute if it may have the - effect of speeding up access to siblings. To save some space, - avoid generating sibling attributes for DIE's without children. */ - -static void -add_sibling_attributes(die) - register dw_die_ref die; -{ - register dw_die_ref c; - register dw_attr_ref attr; - if (die != comp_unit_die && die->die_child != NULL) - { - attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node)); - attr->dw_attr_next = NULL; - attr->dw_attr = DW_AT_sibling; - attr->dw_attr_val.val_class = dw_val_class_die_ref; - attr->dw_attr_val.v.val_die_ref = die->die_sib; - - /* Add the sibling link to the front of the attribute list. */ - attr->dw_attr_next = die->die_attr; - if (die->die_attr == NULL) - die->die_attr_last = attr; - - die->die_attr = attr; - } - - for (c = die->die_child; c != NULL; c = c->die_sib) - add_sibling_attributes (c); -} - -/* The format of each DIE (and its attribute value pairs) - is encoded in an abbreviation table. This routine builds the - abbreviation table and assigns a unique abbreviation id for - each abbreviation entry. The children of each die are visited - recursively. */ - -static void -build_abbrev_table (die) - register dw_die_ref die; -{ - register unsigned long abbrev_id; - register unsigned long n_alloc; - register dw_die_ref c; - register dw_attr_ref d_attr, a_attr; - for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) - { - register dw_die_ref abbrev = abbrev_die_table[abbrev_id]; - - if (abbrev->die_tag == die->die_tag) - { - if ((abbrev->die_child != NULL) == (die->die_child != NULL)) - { - a_attr = abbrev->die_attr; - d_attr = die->die_attr; - - while (a_attr != NULL && d_attr != NULL) - { - if ((a_attr->dw_attr != d_attr->dw_attr) - || (value_format (&a_attr->dw_attr_val) - != value_format (&d_attr->dw_attr_val))) - break; - - a_attr = a_attr->dw_attr_next; - d_attr = d_attr->dw_attr_next; - } - - if (a_attr == NULL && d_attr == NULL) - break; - } - } - } - - if (abbrev_id >= abbrev_die_table_in_use) - { - if (abbrev_die_table_in_use >= abbrev_die_table_allocated) - { - n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT; - abbrev_die_table - = (dw_die_ref *) xrealloc (abbrev_die_table, - sizeof (dw_die_ref) * n_alloc); - - bzero ((char *) &abbrev_die_table[abbrev_die_table_allocated], - (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref)); - abbrev_die_table_allocated = n_alloc; - } - - ++abbrev_die_table_in_use; - abbrev_die_table[abbrev_id] = die; - } - - die->die_abbrev = abbrev_id; - for (c = die->die_child; c != NULL; c = c->die_sib) - build_abbrev_table (c); -} - -/* Return the size of a string, including the null byte. - - This used to treat backslashes as escapes, and hence they were not included - in the count. However, that conflicts with what ASM_OUTPUT_ASCII does, - which treats a backslash as a backslash, escaping it if necessary, and hence - we must include them in the count. */ - -static unsigned long -size_of_string (str) - register char *str; -{ - return strlen (str) + 1; -} - -/* Return the size of a location descriptor. */ - -static unsigned long -size_of_loc_descr (loc) - register dw_loc_descr_ref loc; -{ - register unsigned long size = 1; - - switch (loc->dw_loc_opc) - { - case DW_OP_addr: - size += PTR_SIZE; - break; - case DW_OP_const1u: - case DW_OP_const1s: - size += 1; - break; - case DW_OP_const2u: - case DW_OP_const2s: - size += 2; - break; - case DW_OP_const4u: - case DW_OP_const4s: - size += 4; - break; - case DW_OP_const8u: - case DW_OP_const8s: - size += 8; - break; - case DW_OP_constu: - size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); - break; - case DW_OP_consts: - size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); - break; - case DW_OP_pick: - size += 1; - break; - case DW_OP_plus_uconst: - size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); - break; - case DW_OP_skip: - case DW_OP_bra: - size += 2; - break; - case DW_OP_breg0: - case DW_OP_breg1: - case DW_OP_breg2: - case DW_OP_breg3: - case DW_OP_breg4: - case DW_OP_breg5: - case DW_OP_breg6: - case DW_OP_breg7: - case DW_OP_breg8: - case DW_OP_breg9: - case DW_OP_breg10: - case DW_OP_breg11: - case DW_OP_breg12: - case DW_OP_breg13: - case DW_OP_breg14: - case DW_OP_breg15: - case DW_OP_breg16: - case DW_OP_breg17: - case DW_OP_breg18: - case DW_OP_breg19: - case DW_OP_breg20: - case DW_OP_breg21: - case DW_OP_breg22: - case DW_OP_breg23: - case DW_OP_breg24: - case DW_OP_breg25: - case DW_OP_breg26: - case DW_OP_breg27: - case DW_OP_breg28: - case DW_OP_breg29: - case DW_OP_breg30: - case DW_OP_breg31: - size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); - break; - case DW_OP_regx: - size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); - break; - case DW_OP_fbreg: - size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int); - break; - case DW_OP_bregx: - size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); - size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int); - break; - case DW_OP_piece: - size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); - break; - case DW_OP_deref_size: - case DW_OP_xderef_size: - size += 1; - break; - default: - break; - } - - return size; -} - -/* Return the size of a series of location descriptors. */ - -static unsigned long -size_of_locs (loc) - register dw_loc_descr_ref loc; -{ - register unsigned long size = 0; - - for (; loc != NULL; loc = loc->dw_loc_next) - size += size_of_loc_descr (loc); - - return size; -} - -/* Return the power-of-two number of bytes necessary to represent VALUE. */ - -static int -constant_size (value) - long unsigned value; -{ - int log; - - if (value == 0) - log = 0; - else - log = floor_log2 (value); - - log = log / 8; - log = 1 << (floor_log2 (log) + 1); - - return log; -} - -/* Return the size of a DIE, as it is represented in the - .debug_info section. */ - -static unsigned long -size_of_die (die) - register dw_die_ref die; -{ - register unsigned long size = 0; - register dw_attr_ref a; - - size += size_of_uleb128 (die->die_abbrev); - for (a = die->die_attr; a != NULL; a = a->dw_attr_next) - { - switch (a->dw_attr_val.val_class) - { - case dw_val_class_addr: - size += PTR_SIZE; - break; - case dw_val_class_loc: - { - register unsigned long lsize - = size_of_locs (a->dw_attr_val.v.val_loc); - - /* Block length. */ - size += constant_size (lsize); - size += lsize; - } - break; - case dw_val_class_const: - size += 4; - break; - case dw_val_class_unsigned_const: - size += constant_size (a->dw_attr_val.v.val_unsigned); - break; - case dw_val_class_long_long: - size += 1 + 8; /* block */ - break; - case dw_val_class_float: - size += 1 + a->dw_attr_val.v.val_float.length * 4; /* block */ - break; - case dw_val_class_flag: - size += 1; - break; - case dw_val_class_die_ref: - size += DWARF_OFFSET_SIZE; - break; - case dw_val_class_fde_ref: - size += DWARF_OFFSET_SIZE; - break; - case dw_val_class_lbl_id: - size += PTR_SIZE; - break; - case dw_val_class_lbl_offset: - size += DWARF_OFFSET_SIZE; - break; - case dw_val_class_str: - size += size_of_string (a->dw_attr_val.v.val_str); - break; - default: - abort (); - } - } - - return size; -} - -/* Size the debugging information associated with a given DIE. - Visits the DIE's children recursively. Updates the global - variable next_die_offset, on each time through. Uses the - current value of next_die_offset to update the die_offset - field in each DIE. */ - -static void -calc_die_sizes (die) - dw_die_ref die; -{ - register dw_die_ref c; - die->die_offset = next_die_offset; - next_die_offset += size_of_die (die); - - for (c = die->die_child; c != NULL; c = c->die_sib) - calc_die_sizes (c); - - if (die->die_child != NULL) - /* Count the null byte used to terminate sibling lists. */ - next_die_offset += 1; -} - -/* Return the size of the line information prolog generated for the - compilation unit. */ - -static unsigned long -size_of_line_prolog () -{ - register unsigned long size; - register unsigned long ft_index; - - size = DWARF_LINE_PROLOG_HEADER_SIZE; - - /* Count the size of the table giving number of args for each - standard opcode. */ - size += DWARF_LINE_OPCODE_BASE - 1; - - /* Include directory table is empty (at present). Count only the - null byte used to terminate the table. */ - size += 1; - - for (ft_index = 1; ft_index < file_table_in_use; ++ft_index) - { - /* File name entry. */ - size += size_of_string (file_table[ft_index]); - - /* Include directory index. */ - size += size_of_uleb128 (0); - - /* Modification time. */ - size += size_of_uleb128 (0); - - /* File length in bytes. */ - size += size_of_uleb128 (0); - } - - /* Count the file table terminator. */ - size += 1; - return size; -} - -/* Return the size of the line information generated for this - compilation unit. */ - -static unsigned long -size_of_line_info () -{ - register unsigned long size; - register unsigned long lt_index; - register unsigned long current_line; - register long line_offset; - register long line_delta; - register unsigned long current_file; - register unsigned long function; - unsigned long size_of_set_address; - - /* Size of a DW_LNE_set_address instruction. */ - size_of_set_address = 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE; - - /* Version number. */ - size = 2; - - /* Prolog length specifier. */ - size += DWARF_OFFSET_SIZE; - - /* Prolog. */ - size += size_of_line_prolog (); - - current_file = 1; - current_line = 1; - for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index) - { - register dw_line_info_ref line_info = &line_info_table[lt_index]; - - if (line_info->dw_line_num == current_line - && line_info->dw_file_num == current_file) - continue; - - /* Advance pc instruction. */ - /* ??? See the DW_LNS_advance_pc comment in output_line_info. */ - if (0) - size += 1 + 2; - else - size += size_of_set_address; - - if (line_info->dw_file_num != current_file) - { - /* Set file number instruction. */ - size += 1; - current_file = line_info->dw_file_num; - size += size_of_uleb128 (current_file); - } - - if (line_info->dw_line_num != current_line) - { - line_offset = line_info->dw_line_num - current_line; - line_delta = line_offset - DWARF_LINE_BASE; - current_line = line_info->dw_line_num; - if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) - /* 1-byte special line number instruction. */ - size += 1; - else - { - /* Advance line instruction. */ - size += 1; - size += size_of_sleb128 (line_offset); - /* Generate line entry instruction. */ - size += 1; - } - } - } - - /* Advance pc instruction. */ - if (0) - size += 1 + 2; - else - size += size_of_set_address; - - /* End of line number info. marker. */ - size += 1 + size_of_uleb128 (1) + 1; - - function = 0; - current_file = 1; - current_line = 1; - for (lt_index = 0; lt_index < separate_line_info_table_in_use; ) - { - register dw_separate_line_info_ref line_info - = &separate_line_info_table[lt_index]; - - if (line_info->dw_line_num == current_line - && line_info->dw_file_num == current_file - && line_info->function == function) - goto cont; - - if (function != line_info->function) - { - function = line_info->function; - /* Set address register instruction. */ - size += size_of_set_address; - } - else - { - /* Advance pc instruction. */ - if (0) - size += 1 + 2; - else - size += size_of_set_address; - } - - if (line_info->dw_file_num != current_file) - { - /* Set file number instruction. */ - size += 1; - current_file = line_info->dw_file_num; - size += size_of_uleb128 (current_file); - } - - if (line_info->dw_line_num != current_line) - { - line_offset = line_info->dw_line_num - current_line; - line_delta = line_offset - DWARF_LINE_BASE; - current_line = line_info->dw_line_num; - if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) - /* 1-byte special line number instruction. */ - size += 1; - else - { - /* Advance line instruction. */ - size += 1; - size += size_of_sleb128 (line_offset); - - /* Generate line entry instruction. */ - size += 1; - } - } - - cont: - ++lt_index; - - /* If we're done with a function, end its sequence. */ - if (lt_index == separate_line_info_table_in_use - || separate_line_info_table[lt_index].function != function) - { - current_file = 1; - current_line = 1; - - /* Advance pc instruction. */ - if (0) - size += 1 + 2; - else - size += size_of_set_address; - - /* End of line number info. marker. */ - size += 1 + size_of_uleb128 (1) + 1; - } - } - - return size; -} - -/* Return the size of the .debug_pubnames table generated for the - compilation unit. */ - -static unsigned long -size_of_pubnames () -{ - register unsigned long size; - register unsigned i; - - size = DWARF_PUBNAMES_HEADER_SIZE; - for (i = 0; i < pubname_table_in_use; ++i) - { - register pubname_ref p = &pubname_table[i]; - size += DWARF_OFFSET_SIZE + size_of_string (p->name); - } - - size += DWARF_OFFSET_SIZE; - return size; -} - -/* Return the size of the information in the .debug_aranges section. */ - -static unsigned long -size_of_aranges () -{ - register unsigned long size; - - size = DWARF_ARANGES_HEADER_SIZE; - - /* Count the address/length pair for this compilation unit. */ - size += 2 * PTR_SIZE; - size += 2 * PTR_SIZE * arange_table_in_use; - - /* Count the two zero words used to terminated the address range table. */ - size += 2 * PTR_SIZE; - return size; -} - -/* Select the encoding of an attribute value. */ - -static enum dwarf_form -value_format (v) - dw_val_ref v; -{ - switch (v->val_class) - { - case dw_val_class_addr: - return DW_FORM_addr; - case dw_val_class_loc: - switch (constant_size (size_of_locs (v->v.val_loc))) - { - case 1: - return DW_FORM_block1; - case 2: - return DW_FORM_block2; - default: - abort (); - } - case dw_val_class_const: - return DW_FORM_data4; - case dw_val_class_unsigned_const: - switch (constant_size (v->v.val_unsigned)) - { - case 1: - return DW_FORM_data1; - case 2: - return DW_FORM_data2; - case 4: - return DW_FORM_data4; - case 8: - return DW_FORM_data8; - default: - abort (); - } - case dw_val_class_long_long: - return DW_FORM_block1; - case dw_val_class_float: - return DW_FORM_block1; - case dw_val_class_flag: - return DW_FORM_flag; - case dw_val_class_die_ref: - return DW_FORM_ref; - case dw_val_class_fde_ref: - return DW_FORM_data; - case dw_val_class_lbl_id: - return DW_FORM_addr; - case dw_val_class_lbl_offset: - return DW_FORM_data; - case dw_val_class_str: - return DW_FORM_string; - default: - abort (); - } -} - -/* Output the encoding of an attribute value. */ - -static void -output_value_format (v) - dw_val_ref v; -{ - enum dwarf_form form = value_format (v); - - output_uleb128 (form); - if (flag_debug_asm) - fprintf (asm_out_file, " (%s)", dwarf_form_name (form)); - - fputc ('\n', asm_out_file); -} - -/* Output the .debug_abbrev section which defines the DIE abbreviation - table. */ - -static void -output_abbrev_section () -{ - unsigned long abbrev_id; - - dw_attr_ref a_attr; - for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) - { - register dw_die_ref abbrev = abbrev_die_table[abbrev_id]; - - output_uleb128 (abbrev_id); - if (flag_debug_asm) - fprintf (asm_out_file, " (abbrev code)"); - - fputc ('\n', asm_out_file); - output_uleb128 (abbrev->die_tag); - if (flag_debug_asm) - fprintf (asm_out_file, " (TAG: %s)", - dwarf_tag_name (abbrev->die_tag)); - - fputc ('\n', asm_out_file); - fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, - abbrev->die_child != NULL ? DW_children_yes : DW_children_no); - - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s %s", - ASM_COMMENT_START, - (abbrev->die_child != NULL - ? "DW_children_yes" : "DW_children_no")); - - fputc ('\n', asm_out_file); - - for (a_attr = abbrev->die_attr; a_attr != NULL; - a_attr = a_attr->dw_attr_next) - { - output_uleb128 (a_attr->dw_attr); - if (flag_debug_asm) - fprintf (asm_out_file, " (%s)", - dwarf_attr_name (a_attr->dw_attr)); - - fputc ('\n', asm_out_file); - output_value_format (&a_attr->dw_attr_val); - } - - fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP); - } - - /* We need to properly terminate the abbrev table for this - compilation unit, as per the standard, and not rely on - workarounds in e.g. gdb. */ - fprintf (asm_out_file, "\t%s\t0\n", ASM_BYTE_OP); -} - -/* Output location description stack opcode's operands (if any). */ - -static void -output_loc_operands (loc) - register dw_loc_descr_ref loc; -{ - register dw_val_ref val1 = &loc->dw_loc_oprnd1; - register dw_val_ref val2 = &loc->dw_loc_oprnd2; - - switch (loc->dw_loc_opc) - { - case DW_OP_addr: - ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, val1->v.val_addr); - fputc ('\n', asm_out_file); - break; - case DW_OP_const1u: - case DW_OP_const1s: - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag); - fputc ('\n', asm_out_file); - break; - case DW_OP_const2u: - case DW_OP_const2s: - ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int); - fputc ('\n', asm_out_file); - break; - case DW_OP_const4u: - case DW_OP_const4s: - ASM_OUTPUT_DWARF_DATA4 (asm_out_file, val1->v.val_int); - fputc ('\n', asm_out_file); - break; - case DW_OP_const8u: - case DW_OP_const8s: - abort (); - fputc ('\n', asm_out_file); - break; - case DW_OP_constu: - output_uleb128 (val1->v.val_unsigned); - fputc ('\n', asm_out_file); - break; - case DW_OP_consts: - output_sleb128 (val1->v.val_int); - fputc ('\n', asm_out_file); - break; - case DW_OP_pick: - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_int); - fputc ('\n', asm_out_file); - break; - case DW_OP_plus_uconst: - output_uleb128 (val1->v.val_unsigned); - fputc ('\n', asm_out_file); - break; - case DW_OP_skip: - case DW_OP_bra: - ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int); - fputc ('\n', asm_out_file); - break; - case DW_OP_breg0: - case DW_OP_breg1: - case DW_OP_breg2: - case DW_OP_breg3: - case DW_OP_breg4: - case DW_OP_breg5: - case DW_OP_breg6: - case DW_OP_breg7: - case DW_OP_breg8: - case DW_OP_breg9: - case DW_OP_breg10: - case DW_OP_breg11: - case DW_OP_breg12: - case DW_OP_breg13: - case DW_OP_breg14: - case DW_OP_breg15: - case DW_OP_breg16: - case DW_OP_breg17: - case DW_OP_breg18: - case DW_OP_breg19: - case DW_OP_breg20: - case DW_OP_breg21: - case DW_OP_breg22: - case DW_OP_breg23: - case DW_OP_breg24: - case DW_OP_breg25: - case DW_OP_breg26: - case DW_OP_breg27: - case DW_OP_breg28: - case DW_OP_breg29: - case DW_OP_breg30: - case DW_OP_breg31: - output_sleb128 (val1->v.val_int); - fputc ('\n', asm_out_file); - break; - case DW_OP_regx: - output_uleb128 (val1->v.val_unsigned); - fputc ('\n', asm_out_file); - break; - case DW_OP_fbreg: - output_sleb128 (val1->v.val_int); - fputc ('\n', asm_out_file); - break; - case DW_OP_bregx: - output_uleb128 (val1->v.val_unsigned); - fputc ('\n', asm_out_file); - output_sleb128 (val2->v.val_int); - fputc ('\n', asm_out_file); - break; - case DW_OP_piece: - output_uleb128 (val1->v.val_unsigned); - fputc ('\n', asm_out_file); - break; - case DW_OP_deref_size: - case DW_OP_xderef_size: - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag); - fputc ('\n', asm_out_file); - break; - default: - break; - } -} - -/* Compute the offset of a sibling. */ - -static unsigned long -sibling_offset (die) - dw_die_ref die; -{ - unsigned long offset; - - if (die->die_child_last == NULL) - offset = die->die_offset + size_of_die (die); - else - offset = sibling_offset (die->die_child_last) + 1; - - return offset; -} - -/* Output the DIE and its attributes. Called recursively to generate - the definitions of each child DIE. */ - -static void -output_die (die) - register dw_die_ref die; -{ - register dw_attr_ref a; - register dw_die_ref c; - register unsigned long ref_offset; - register unsigned long size; - register dw_loc_descr_ref loc; - - output_uleb128 (die->die_abbrev); - if (flag_debug_asm) - fprintf (asm_out_file, " (DIE (0x%lx) %s)", - die->die_offset, dwarf_tag_name (die->die_tag)); - - fputc ('\n', asm_out_file); - - for (a = die->die_attr; a != NULL; a = a->dw_attr_next) - { - switch (a->dw_attr_val.val_class) - { - case dw_val_class_addr: - ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, - a->dw_attr_val.v.val_addr); - break; - - case dw_val_class_loc: - size = size_of_locs (a->dw_attr_val.v.val_loc); - - /* Output the block length for this list of location operations. */ - switch (constant_size (size)) - { - case 1: - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, size); - break; - case 2: - ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size); - break; - default: - abort (); - } - - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s %s", - ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); - - fputc ('\n', asm_out_file); - for (loc = a->dw_attr_val.v.val_loc; loc != NULL; - loc = loc->dw_loc_next) - { - /* Output the opcode. */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, loc->dw_loc_opc); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START, - dwarf_stack_op_name (loc->dw_loc_opc)); - - fputc ('\n', asm_out_file); - - /* Output the operand(s) (if any). */ - output_loc_operands (loc); - } - break; - - case dw_val_class_const: - ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_int); - break; - - case dw_val_class_unsigned_const: - switch (constant_size (a->dw_attr_val.v.val_unsigned)) - { - case 1: - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, - a->dw_attr_val.v.val_unsigned); - break; - case 2: - ASM_OUTPUT_DWARF_DATA2 (asm_out_file, - a->dw_attr_val.v.val_unsigned); - break; - case 4: - ASM_OUTPUT_DWARF_DATA4 (asm_out_file, - a->dw_attr_val.v.val_unsigned); - break; - case 8: - ASM_OUTPUT_DWARF_DATA8 (asm_out_file, - a->dw_attr_val.v.val_long_long.hi, - a->dw_attr_val.v.val_long_long.low); - break; - default: - abort (); - } - break; - - case dw_val_class_long_long: - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 8); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s %s", - ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA8 (asm_out_file, - a->dw_attr_val.v.val_long_long.hi, - a->dw_attr_val.v.val_long_long.low); - - if (flag_debug_asm) - fprintf (asm_out_file, - "\t%s long long constant", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - break; - - case dw_val_class_float: - { - register unsigned int i; - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, - a->dw_attr_val.v.val_float.length * 4); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s %s", - ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); - - fputc ('\n', asm_out_file); - for (i = 0; i < a->dw_attr_val.v.val_float.length; ++i) - { - ASM_OUTPUT_DWARF_DATA4 (asm_out_file, - a->dw_attr_val.v.val_float.array[i]); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s fp constant word %u", - ASM_COMMENT_START, i); - - fputc ('\n', asm_out_file); - } - break; - } - - case dw_val_class_flag: - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, a->dw_attr_val.v.val_flag); - break; - - case dw_val_class_die_ref: - if (a->dw_attr_val.v.val_die_ref != NULL) - ref_offset = a->dw_attr_val.v.val_die_ref->die_offset; - else if (a->dw_attr == DW_AT_sibling) - ref_offset = sibling_offset(die); - else - abort (); - - ASM_OUTPUT_DWARF_DATA (asm_out_file, ref_offset); - break; - - case dw_val_class_fde_ref: - { - char l1[20]; - ASM_GENERATE_INTERNAL_LABEL - (l1, FDE_AFTER_SIZE_LABEL, a->dw_attr_val.v.val_fde_index * 2); - ASM_OUTPUT_DWARF_OFFSET (asm_out_file, l1); - fprintf (asm_out_file, " - %d", DWARF_OFFSET_SIZE); - } - break; - - case dw_val_class_lbl_id: - ASM_OUTPUT_DWARF_ADDR (asm_out_file, a->dw_attr_val.v.val_lbl_id); - break; - - case dw_val_class_lbl_offset: - ASM_OUTPUT_DWARF_OFFSET (asm_out_file, a->dw_attr_val.v.val_lbl_id); - break; - - case dw_val_class_str: - if (flag_debug_asm) - ASM_OUTPUT_DWARF_STRING (asm_out_file, a->dw_attr_val.v.val_str); - else - ASM_OUTPUT_ASCII (asm_out_file, - a->dw_attr_val.v.val_str, - (int) strlen (a->dw_attr_val.v.val_str) + 1); - break; - - default: - abort (); - } - - if (a->dw_attr_val.val_class != dw_val_class_loc - && a->dw_attr_val.val_class != dw_val_class_long_long - && a->dw_attr_val.val_class != dw_val_class_float) - { - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s %s", - ASM_COMMENT_START, dwarf_attr_name (a->dw_attr)); - - fputc ('\n', asm_out_file); - } - } - - for (c = die->die_child; c != NULL; c = c->die_sib) - output_die (c); - - if (die->die_child != NULL) - { - /* Add null byte to terminate sibling list. */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s end of children of DIE 0x%lx", - ASM_COMMENT_START, die->die_offset); - - fputc ('\n', asm_out_file); - } -} - -/* Output the compilation unit that appears at the beginning of the - .debug_info section, and precedes the DIE descriptions. */ - -static void -output_compilation_unit_header () -{ - ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset - DWARF_OFFSET_SIZE); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DWARF version number", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_OFFSET (asm_out_file, abbrev_section_label); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Pointer Size (in bytes)", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); -} - -/* The DWARF2 pubname for a nested thingy looks like "A::f". The output - of decl_printable_name for C++ looks like "A::f(int)". Let's drop the - argument list, and maybe the scope. */ - -static char * -dwarf2_name (decl, scope) - tree decl; - int scope; -{ - return (*decl_printable_name) (decl, scope ? 1 : 0); -} - -/* Add a new entry to .debug_pubnames if appropriate. */ - -static void -add_pubname (decl, die) - tree decl; - dw_die_ref die; -{ - pubname_ref p; - - if (! TREE_PUBLIC (decl)) - return; - - if (pubname_table_in_use == pubname_table_allocated) - { - pubname_table_allocated += PUBNAME_TABLE_INCREMENT; - pubname_table = (pubname_ref) xrealloc - (pubname_table, pubname_table_allocated * sizeof (pubname_entry)); - } - - p = &pubname_table[pubname_table_in_use++]; - p->die = die; - - p->name = xstrdup (dwarf2_name (decl, 1)); -} - -/* Output the public names table used to speed up access to externally - visible names. For now, only generate entries for externally - visible procedures. */ - -static void -output_pubnames () -{ - register unsigned i; - register unsigned long pubnames_length = size_of_pubnames (); - - ASM_OUTPUT_DWARF_DATA (asm_out_file, pubnames_length); - - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Length of Public Names Info.", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); - - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_OFFSET (asm_out_file, debug_info_section_label); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Compilation Unit Length", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - for (i = 0; i < pubname_table_in_use; ++i) - { - register pubname_ref pub = &pubname_table[i]; - - ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - - if (flag_debug_asm) - { - ASM_OUTPUT_DWARF_STRING (asm_out_file, pub->name); - fprintf (asm_out_file, "%s external name", ASM_COMMENT_START); - } - else - { - ASM_OUTPUT_ASCII (asm_out_file, pub->name, - (int) strlen (pub->name) + 1); - } - - fputc ('\n', asm_out_file); - } - - ASM_OUTPUT_DWARF_DATA (asm_out_file, 0); - fputc ('\n', asm_out_file); -} - -/* Add a new entry to .debug_aranges if appropriate. */ - -static void -add_arange (decl, die) - tree decl; - dw_die_ref die; -{ - if (! DECL_SECTION_NAME (decl)) - return; - - if (arange_table_in_use == arange_table_allocated) - { - arange_table_allocated += ARANGE_TABLE_INCREMENT; - arange_table - = (arange_ref) xrealloc (arange_table, - arange_table_allocated * sizeof (dw_die_ref)); - } - - arange_table[arange_table_in_use++] = die; -} - -/* Output the information that goes into the .debug_aranges table. - Namely, define the beginning and ending address range of the - text section generated for this compilation unit. */ - -static void -output_aranges () -{ - register unsigned i; - register unsigned long aranges_length = size_of_aranges (); - - ASM_OUTPUT_DWARF_DATA (asm_out_file, aranges_length); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Length of Address Ranges Info.", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_OFFSET (asm_out_file, debug_info_section_label); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Size of Address", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Size of Segment Descriptor", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 4); - if (PTR_SIZE == 8) - fprintf (asm_out_file, ",0,0"); - - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Pad to %d byte boundary", - ASM_COMMENT_START, 2 * PTR_SIZE); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_section_label); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, text_end_label, - text_section_label); - if (flag_debug_asm) - fprintf (asm_out_file, "%s Length", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - for (i = 0; i < arange_table_in_use; ++i) - { - dw_die_ref a = arange_table[i]; - - if (a->die_tag == DW_TAG_subprogram) - ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (a)); - else - { - char *name = get_AT_string (a, DW_AT_MIPS_linkage_name); - if (! name) - name = get_AT_string (a, DW_AT_name); - - ASM_OUTPUT_DWARF_ADDR (asm_out_file, name); - } - - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - if (a->die_tag == DW_TAG_subprogram) - ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, get_AT_hi_pc (a), - get_AT_low_pc (a)); - else - ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, - get_AT_unsigned (a, DW_AT_byte_size)); - - if (flag_debug_asm) - fprintf (asm_out_file, "%s Length", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - } - - /* Output the terminator words. */ - ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0); - fputc ('\n', asm_out_file); -} - -/* Output the source line number correspondence information. This - information goes into the .debug_line section. - - If the format of this data changes, then the function size_of_line_info - must also be adjusted the same way. */ - -static void -output_line_info () -{ - char line_label[MAX_ARTIFICIAL_LABEL_BYTES]; - char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES]; - register unsigned opc; - register unsigned n_op_args; - register unsigned long ft_index; - register unsigned long lt_index; - register unsigned long current_line; - register long line_offset; - register long line_delta; - register unsigned long current_file; - register unsigned long function; - - ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_info ()); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Length of Source Line Info.", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_prolog ()); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Prolog Length", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_MIN_INSTR_LENGTH); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Minimum Instruction Length", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_DEFAULT_IS_STMT_START); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Default is_stmt_start flag", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - fprintf (asm_out_file, "\t%s\t%d", ASM_BYTE_OP, DWARF_LINE_BASE); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Line Base Value (Special Opcodes)", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_RANGE); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Line Range Value (Special Opcodes)", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_OPCODE_BASE); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s Special Opcode Base", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; ++opc) - { - switch (opc) - { - case DW_LNS_advance_pc: - case DW_LNS_advance_line: - case DW_LNS_set_file: - case DW_LNS_set_column: - case DW_LNS_fixed_advance_pc: - n_op_args = 1; - break; - default: - n_op_args = 0; - break; - } - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, n_op_args); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s opcode: 0x%x has %d args", - ASM_COMMENT_START, opc, n_op_args); - fputc ('\n', asm_out_file); - } - - if (flag_debug_asm) - fprintf (asm_out_file, "%s Include Directory Table\n", ASM_COMMENT_START); - - /* Include directory table is empty, at present */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - fputc ('\n', asm_out_file); - if (flag_debug_asm) - fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START); - - for (ft_index = 1; ft_index < file_table_in_use; ++ft_index) - { - if (flag_debug_asm) - { - ASM_OUTPUT_DWARF_STRING (asm_out_file, file_table[ft_index]); - fprintf (asm_out_file, "%s File Entry: 0x%lx", - ASM_COMMENT_START, ft_index); - } - else - { - ASM_OUTPUT_ASCII (asm_out_file, - file_table[ft_index], - (int) strlen (file_table[ft_index]) + 1); - } - - fputc ('\n', asm_out_file); - - /* Include directory index */ - output_uleb128 (0); - fputc ('\n', asm_out_file); - - /* Modification time */ - output_uleb128 (0); - fputc ('\n', asm_out_file); - - /* File length in bytes */ - output_uleb128 (0); - fputc ('\n', asm_out_file); - } - - /* Terminate the file name table */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - fputc ('\n', asm_out_file); - - /* We used to set the address register to the first location in the text - section here, but that didn't accomplish anything since we already - have a line note for the opening brace of the first function. */ - - /* Generate the line number to PC correspondence table, encoded as - a series of state machine operations. */ - current_file = 1; - current_line = 1; - strcpy (prev_line_label, text_section_label); - for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index) - { - register dw_line_info_ref line_info = &line_info_table[lt_index]; - - /* Don't emit anything for redundant notes. Just updating the - address doesn't accomplish anything, because we already assume - that anything after the last address is this line. */ - if (line_info->dw_line_num == current_line - && line_info->dw_file_num == current_file) - continue; - - /* Emit debug info for the address of the current line, choosing - the encoding that uses the least amount of space. */ - /* ??? Unfortunately, we have little choice here currently, and must - always use the most general form. Gcc does not know the address - delta itself, so we can't use DW_LNS_advance_pc. There are no known - dwarf2 aware assemblers at this time, so we can't use any special - pseudo ops that would allow the assembler to optimally encode this for - us. Many ports do have length attributes which will give an upper - bound on the address range. We could perhaps use length attributes - to determine when it is safe to use DW_LNS_fixed_advance_pc. */ - ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index); - if (0) - { - /* This can handle deltas up to 0xffff. This takes 3 bytes. */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label); - fputc ('\n', asm_out_file); - } - else - { - /* This can handle any delta. This takes 4+PTR_SIZE bytes. */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNE_set_address", - ASM_COMMENT_START); - fputc ('\n', asm_out_file); - output_uleb128 (1 + PTR_SIZE); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); - fputc ('\n', asm_out_file); - } - strcpy (prev_line_label, line_label); - - /* Emit debug info for the source file of the current line, if - different from the previous line. */ - if (line_info->dw_file_num != current_file) - { - current_file = line_info->dw_file_num; - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - output_uleb128 (current_file); - if (flag_debug_asm) - fprintf (asm_out_file, " (\"%s\")", file_table[current_file]); - - fputc ('\n', asm_out_file); - } - - /* Emit debug info for the current line number, choosing the encoding - that uses the least amount of space. */ - if (line_info->dw_line_num != current_line) - { - line_offset = line_info->dw_line_num - current_line; - line_delta = line_offset - DWARF_LINE_BASE; - current_line = line_info->dw_line_num; - if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) - { - /* This can handle deltas from -10 to 234, using the current - definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE. This - takes 1 byte. */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, - DWARF_LINE_OPCODE_BASE + line_delta); - if (flag_debug_asm) - fprintf (asm_out_file, - "\t%s line %ld", ASM_COMMENT_START, current_line); - - fputc ('\n', asm_out_file); - } - else - { - /* This can handle any delta. This takes at least 4 bytes, - depending on the value being encoded. */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s advance to line %ld", - ASM_COMMENT_START, current_line); - - fputc ('\n', asm_out_file); - output_sleb128 (line_offset); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START); - fputc ('\n', asm_out_file); - } - } - else - { - /* We still need to start a new row, so output a copy insn. */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START); - fputc ('\n', asm_out_file); - } - } - - /* Emit debug info for the address of the end of the function. */ - if (0) - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, text_end_label, prev_line_label); - fputc ('\n', asm_out_file); - } - else - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START); - fputc ('\n', asm_out_file); - output_uleb128 (1 + PTR_SIZE); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_end_label); - fputc ('\n', asm_out_file); - } - - /* Output the marker for the end of the line number info. */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - output_uleb128 (1); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence); - fputc ('\n', asm_out_file); - - function = 0; - current_file = 1; - current_line = 1; - for (lt_index = 0; lt_index < separate_line_info_table_in_use; ) - { - register dw_separate_line_info_ref line_info - = &separate_line_info_table[lt_index]; - - /* Don't emit anything for redundant notes. */ - if (line_info->dw_line_num == current_line - && line_info->dw_file_num == current_file - && line_info->function == function) - goto cont; - - /* Emit debug info for the address of the current line. If this is - a new function, or the first line of a function, then we need - to handle it differently. */ - ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL, - lt_index); - if (function != line_info->function) - { - function = line_info->function; - - /* Set the address register to the first line in the function */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNE_set_address", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - output_uleb128 (1 + PTR_SIZE); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); - fputc ('\n', asm_out_file); - } - else - { - /* ??? See the DW_LNS_advance_pc comment above. */ - if (0) - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, - prev_line_label); - fputc ('\n', asm_out_file); - } - else - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNE_set_address", - ASM_COMMENT_START); - fputc ('\n', asm_out_file); - output_uleb128 (1 + PTR_SIZE); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); - fputc ('\n', asm_out_file); - } - } - strcpy (prev_line_label, line_label); - - /* Emit debug info for the source file of the current line, if - different from the previous line. */ - if (line_info->dw_file_num != current_file) - { - current_file = line_info->dw_file_num; - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - output_uleb128 (current_file); - if (flag_debug_asm) - fprintf (asm_out_file, " (\"%s\")", file_table[current_file]); - - fputc ('\n', asm_out_file); - } - - /* Emit debug info for the current line number, choosing the encoding - that uses the least amount of space. */ - if (line_info->dw_line_num != current_line) - { - line_offset = line_info->dw_line_num - current_line; - line_delta = line_offset - DWARF_LINE_BASE; - current_line = line_info->dw_line_num; - if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, - DWARF_LINE_OPCODE_BASE + line_delta); - if (flag_debug_asm) - fprintf (asm_out_file, - "\t%s line %ld", ASM_COMMENT_START, current_line); - - fputc ('\n', asm_out_file); - } - else - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s advance to line %ld", - ASM_COMMENT_START, current_line); - - fputc ('\n', asm_out_file); - output_sleb128 (line_offset); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START); - fputc ('\n', asm_out_file); - } - } - else - { - /* We still need to start a new row, so output a copy insn. */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START); - fputc ('\n', asm_out_file); - } - - cont: - ++lt_index; - - /* If we're done with a function, end its sequence. */ - if (lt_index == separate_line_info_table_in_use - || separate_line_info_table[lt_index].function != function) - { - current_file = 1; - current_line = 1; - - /* Emit debug info for the address of the end of the function. */ - ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function); - if (0) - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, - prev_line_label); - fputc ('\n', asm_out_file); - } - else - { - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNE_set_address", - ASM_COMMENT_START); - fputc ('\n', asm_out_file); - output_uleb128 (1 + PTR_SIZE); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label); - fputc ('\n', asm_out_file); - } - - /* Output the marker for the end of this sequence. */ - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0); - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", - ASM_COMMENT_START); - - fputc ('\n', asm_out_file); - output_uleb128 (1); - fputc ('\n', asm_out_file); - ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence); - fputc ('\n', asm_out_file); - } - } -} - -/* Given a pointer to a BLOCK node return non-zero if (and only if) the node - in question represents the outermost pair of curly braces (i.e. the "body - block") of a function or method. - - For any BLOCK node representing a "body block" of a function or method, the - BLOCK_SUPERCONTEXT of the node will point to another BLOCK node which - represents the outermost (function) scope for the function or method (i.e. - the one which includes the formal parameters). The BLOCK_SUPERCONTEXT of - *that* node in turn will point to the relevant FUNCTION_DECL node. */ - -static inline int -is_body_block (stmt) - register tree stmt; -{ - if (TREE_CODE (stmt) == BLOCK) - { - register tree parent = BLOCK_SUPERCONTEXT (stmt); - - if (TREE_CODE (parent) == BLOCK) - { - register tree grandparent = BLOCK_SUPERCONTEXT (parent); - - if (TREE_CODE (grandparent) == FUNCTION_DECL) - return 1; - } - } - - return 0; -} - -/* Given a pointer to a tree node for some base type, return a pointer to - a DIE that describes the given type. - - This routine must only be called for GCC type nodes that correspond to - Dwarf base (fundamental) types. */ - -static dw_die_ref -base_type_die (type) - register tree type; -{ - register dw_die_ref base_type_result; - register char *type_name; - register enum dwarf_type encoding; - register tree name = TYPE_NAME (type); - - if (TREE_CODE (type) == ERROR_MARK - || TREE_CODE (type) == VOID_TYPE) - return 0; - - if (TREE_CODE (name) == TYPE_DECL) - name = DECL_NAME (name); - type_name = IDENTIFIER_POINTER (name); - - switch (TREE_CODE (type)) - { - case INTEGER_TYPE: - /* Carefully distinguish the C character types, without messing - up if the language is not C. Note that we check only for the names - that contain spaces; other names might occur by coincidence in other - languages. */ - if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE - && (type == char_type_node - || ! strcmp (type_name, "signed char") - || ! strcmp (type_name, "unsigned char")))) - { - if (TREE_UNSIGNED (type)) - encoding = DW_ATE_unsigned; - else - encoding = DW_ATE_signed; - break; - } - /* else fall through */ - - case CHAR_TYPE: - /* GNU Pascal/Ada CHAR type. Not used in C. */ - if (TREE_UNSIGNED (type)) - encoding = DW_ATE_unsigned_char; - else - encoding = DW_ATE_signed_char; - break; - - case REAL_TYPE: - encoding = DW_ATE_float; - break; - - case COMPLEX_TYPE: - encoding = DW_ATE_complex_float; - break; - - case BOOLEAN_TYPE: - /* GNU FORTRAN/Ada/C++ BOOLEAN type. */ - encoding = DW_ATE_boolean; - break; - - default: - abort (); /* No other TREE_CODEs are Dwarf fundamental types. */ - } - - base_type_result = new_die (DW_TAG_base_type, comp_unit_die); - add_AT_string (base_type_result, DW_AT_name, type_name); - add_AT_unsigned (base_type_result, DW_AT_byte_size, - int_size_in_bytes (type)); - add_AT_unsigned (base_type_result, DW_AT_encoding, encoding); - - return base_type_result; -} - -/* Given a pointer to an arbitrary ..._TYPE tree node, return a pointer to - the Dwarf "root" type for the given input type. The Dwarf "root" type of - a given type is generally the same as the given type, except that if the - given type is a pointer or reference type, then the root type of the given - type is the root type of the "basis" type for the pointer or reference - type. (This definition of the "root" type is recursive.) Also, the root - type of a `const' qualified type or a `volatile' qualified type is the - root type of the given type without the qualifiers. */ - -static tree -root_type (type) - register tree type; -{ - if (TREE_CODE (type) == ERROR_MARK) - return error_mark_node; - - switch (TREE_CODE (type)) - { - case ERROR_MARK: - return error_mark_node; - - case POINTER_TYPE: - case REFERENCE_TYPE: - return type_main_variant (root_type (TREE_TYPE (type))); - - default: - return type_main_variant (type); - } -} - -/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the - given input type is a Dwarf "fundamental" type. Otherwise return null. */ - -static inline int -is_base_type (type) - register tree type; -{ - switch (TREE_CODE (type)) - { - case ERROR_MARK: - case VOID_TYPE: - case INTEGER_TYPE: - case REAL_TYPE: - case COMPLEX_TYPE: - case BOOLEAN_TYPE: - case CHAR_TYPE: - return 1; - - case SET_TYPE: - case ARRAY_TYPE: - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - case ENUMERAL_TYPE: - case FUNCTION_TYPE: - case METHOD_TYPE: - case POINTER_TYPE: - case REFERENCE_TYPE: - case FILE_TYPE: - case OFFSET_TYPE: - case LANG_TYPE: - return 0; - - default: - abort (); - } - - return 0; -} - -/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging - entry that chains various modifiers in front of the given type. */ - -static dw_die_ref -modified_type_die (type, is_const_type, is_volatile_type, context_die) - register tree type; - register int is_const_type; - register int is_volatile_type; - register dw_die_ref context_die; -{ - register enum tree_code code = TREE_CODE (type); - register dw_die_ref mod_type_die = NULL; - register dw_die_ref sub_die = NULL; - register tree item_type = NULL; - - if (code != ERROR_MARK) - { - type = build_type_variant (type, is_const_type, is_volatile_type); - - mod_type_die = lookup_type_die (type); - if (mod_type_die) - return mod_type_die; - - /* Handle C typedef types. */ - if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) - { - tree dtype = TREE_TYPE (TYPE_NAME (type)); - if (type == dtype) - { - /* For a named type, use the typedef. */ - gen_type_die (type, context_die); - mod_type_die = lookup_type_die (type); - } - - else if (is_const_type < TYPE_READONLY (dtype) - || is_volatile_type < TYPE_VOLATILE (dtype)) - /* cv-unqualified version of named type. Just use the unnamed - type to which it refers. */ - mod_type_die - = modified_type_die (DECL_ORIGINAL_TYPE (TYPE_NAME (type)), - is_const_type, is_volatile_type, - context_die); - /* Else cv-qualified version of named type; fall through. */ - } - - if (mod_type_die) - /* OK */; - else if (is_const_type) - { - mod_type_die = new_die (DW_TAG_const_type, comp_unit_die); - sub_die = modified_type_die (type, 0, is_volatile_type, context_die); - } - else if (is_volatile_type) - { - mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die); - sub_die = modified_type_die (type, 0, 0, context_die); - } - else if (code == POINTER_TYPE) - { - mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die); - add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); -#if 0 - add_AT_unsigned (mod_type_die, DW_AT_address_class, 0); -#endif - item_type = TREE_TYPE (type); - } - else if (code == REFERENCE_TYPE) - { - mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die); - add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); -#if 0 - add_AT_unsigned (mod_type_die, DW_AT_address_class, 0); -#endif - item_type = TREE_TYPE (type); - } - else if (is_base_type (type)) - mod_type_die = base_type_die (type); - else - { - gen_type_die (type, context_die); - - /* We have to get the type_main_variant here (and pass that to the - `lookup_type_die' routine) because the ..._TYPE node we have - might simply be a *copy* of some original type node (where the - copy was created to help us keep track of typedef names) and - that copy might have a different TYPE_UID from the original - ..._TYPE node. */ - mod_type_die = lookup_type_die (type_main_variant (type)); - if (mod_type_die == NULL) - abort (); - } - } - - equate_type_number_to_die (type, mod_type_die); - if (item_type) - /* We must do this after the equate_type_number_to_die call, in case - this is a recursive type. This ensures that the modified_type_die - recursion will terminate even if the type is recursive. Recursive - types are possible in Ada. */ - sub_die = modified_type_die (item_type, - TYPE_READONLY (item_type), - TYPE_VOLATILE (item_type), - context_die); - - if (sub_die != NULL) - add_AT_die_ref (mod_type_die, DW_AT_type, sub_die); - - return mod_type_die; -} - -/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is - an enumerated type. */ - -static inline int -type_is_enum (type) - register tree type; -{ - return TREE_CODE (type) == ENUMERAL_TYPE; -} - -/* Return a location descriptor that designates a machine register. */ - -static dw_loc_descr_ref -reg_loc_descriptor (rtl) - register rtx rtl; -{ - register dw_loc_descr_ref loc_result = NULL; - register unsigned reg = reg_number (rtl); - - if (reg <= 31) - loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0); - else - loc_result = new_loc_descr (DW_OP_regx, reg, 0); - - return loc_result; -} - -/* Return a location descriptor that designates a base+offset location. */ - -static dw_loc_descr_ref -based_loc_descr (reg, offset) - unsigned reg; - long int offset; -{ - register dw_loc_descr_ref loc_result; - /* For the "frame base", we use the frame pointer or stack pointer - registers, since the RTL for local variables is relative to one of - them. */ - register unsigned fp_reg = DBX_REGISTER_NUMBER (frame_pointer_needed - ? HARD_FRAME_POINTER_REGNUM - : STACK_POINTER_REGNUM); - - if (reg == fp_reg) - loc_result = new_loc_descr (DW_OP_fbreg, offset, 0); - else if (reg <= 31) - loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0); - else - loc_result = new_loc_descr (DW_OP_bregx, reg, offset); - - return loc_result; -} - -/* Return true if this RTL expression describes a base+offset calculation. */ - -static inline int -is_based_loc (rtl) - register rtx rtl; -{ - return (GET_CODE (rtl) == PLUS - && ((GET_CODE (XEXP (rtl, 0)) == REG - && GET_CODE (XEXP (rtl, 1)) == CONST_INT))); -} - -/* The following routine converts the RTL for a variable or parameter - (resident in memory) into an equivalent Dwarf representation of a - mechanism for getting the address of that same variable onto the top of a - hypothetical "address evaluation" stack. - - When creating memory location descriptors, we are effectively transforming - the RTL for a memory-resident object into its Dwarf postfix expression - equivalent. This routine recursively descends an RTL tree, turning - it into Dwarf postfix code as it goes. */ - -static dw_loc_descr_ref -mem_loc_descriptor (rtl) - register rtx rtl; -{ - dw_loc_descr_ref mem_loc_result = NULL; - /* Note that for a dynamically sized array, the location we will generate a - description of here will be the lowest numbered location which is - actually within the array. That's *not* necessarily the same as the - zeroth element of the array. */ - - switch (GET_CODE (rtl)) - { - case SUBREG: - /* The case of a subreg may arise when we have a local (register) - variable or a formal (register) parameter which doesn't quite fill - up an entire register. For now, just assume that it is - legitimate to make the Dwarf info refer to the whole register which - contains the given subreg. */ - rtl = XEXP (rtl, 0); - - /* ... fall through ... */ - - case REG: - /* Whenever a register number forms a part of the description of the - method for calculating the (dynamic) address of a memory resident - object, DWARF rules require the register number be referred to as - a "base register". This distinction is not based in any way upon - what category of register the hardware believes the given register - belongs to. This is strictly DWARF terminology we're dealing with - here. Note that in cases where the location of a memory-resident - data object could be expressed as: OP_ADD (OP_BASEREG (basereg), - OP_CONST (0)) the actual DWARF location descriptor that we generate - may just be OP_BASEREG (basereg). This may look deceptively like - the object in question was allocated to a register (rather than in - memory) so DWARF consumers need to be aware of the subtle - distinction between OP_REG and OP_BASEREG. */ - mem_loc_result = based_loc_descr (reg_number (rtl), 0); - break; - - case MEM: - mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0)); - add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0)); - break; - - case CONST: - case SYMBOL_REF: - mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0); - mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr; - mem_loc_result->dw_loc_oprnd1.v.val_addr = addr_to_string (rtl); - break; - - case PLUS: - if (is_based_loc (rtl)) - mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)), - INTVAL (XEXP (rtl, 1))); - else - { - add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0))); - add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1))); - add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0)); - } - break; - - case MULT: - /* If a pseudo-reg is optimized away, it is possible for it to - be replaced with a MEM containing a multiply. */ - add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0))); - add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1))); - add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0)); - break; - - case CONST_INT: - mem_loc_result = new_loc_descr (DW_OP_constu, INTVAL (rtl), 0); - break; - - default: - abort (); - } - - return mem_loc_result; -} - -/* Return a descriptor that describes the concatenation of two locations. - This is typically a complex variable. */ - -static dw_loc_descr_ref -concat_loc_descriptor (x0, x1) - register rtx x0, x1; -{ - dw_loc_descr_ref cc_loc_result = NULL; - - if (!is_pseudo_reg (x0) - && (GET_CODE (x0) != MEM || !is_pseudo_reg (XEXP (x0, 0)))) - add_loc_descr (&cc_loc_result, loc_descriptor (x0)); - add_loc_descr (&cc_loc_result, - new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x0)), 0)); - - if (!is_pseudo_reg (x1) - && (GET_CODE (x1) != MEM || !is_pseudo_reg (XEXP (x1, 0)))) - add_loc_descr (&cc_loc_result, loc_descriptor (x1)); - add_loc_descr (&cc_loc_result, - new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x1)), 0)); - - return cc_loc_result; -} - -/* Output a proper Dwarf location descriptor for a variable or parameter - which is either allocated in a register or in a memory location. For a - register, we just generate an OP_REG and the register number. For a - memory location we provide a Dwarf postfix expression describing how to - generate the (dynamic) address of the object onto the address stack. */ - -static dw_loc_descr_ref -loc_descriptor (rtl) - register rtx rtl; -{ - dw_loc_descr_ref loc_result = NULL; - switch (GET_CODE (rtl)) - { - case SUBREG: - /* The case of a subreg may arise when we have a local (register) - variable or a formal (register) parameter which doesn't quite fill - up an entire register. For now, just assume that it is - legitimate to make the Dwarf info refer to the whole register which - contains the given subreg. */ - rtl = XEXP (rtl, 0); - - /* ... fall through ... */ - - case REG: - loc_result = reg_loc_descriptor (rtl); - break; - - case MEM: - loc_result = mem_loc_descriptor (XEXP (rtl, 0)); - break; - - case CONCAT: - loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1)); - break; - - default: - abort (); - } - - return loc_result; -} - -/* Given an unsigned value, round it up to the lowest multiple of `boundary' - which is not less than the value itself. */ - -static inline unsigned -ceiling (value, boundary) - register unsigned value; - register unsigned boundary; -{ - return (((value + boundary - 1) / boundary) * boundary); -} - -/* Given a pointer to what is assumed to be a FIELD_DECL node, return a - pointer to the declared type for the relevant field variable, or return - `integer_type_node' if the given node turns out to be an - ERROR_MARK node. */ - -static inline tree -field_type (decl) - register tree decl; -{ - register tree type; - - if (TREE_CODE (decl) == ERROR_MARK) - return integer_type_node; - - type = DECL_BIT_FIELD_TYPE (decl); - if (type == NULL_TREE) - type = TREE_TYPE (decl); - - return type; -} - -/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE - node, return the alignment in bits for the type, or else return - BITS_PER_WORD if the node actually turns out to be an - ERROR_MARK node. */ - -static inline unsigned -simple_type_align_in_bits (type) - register tree type; -{ - return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD; -} - -/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE - node, return the size in bits for the type if it is a constant, or else - return the alignment for the type if the type's size is not constant, or - else return BITS_PER_WORD if the type actually turns out to be an - ERROR_MARK node. */ - -static inline unsigned -simple_type_size_in_bits (type) - register tree type; -{ - if (TREE_CODE (type) == ERROR_MARK) - return BITS_PER_WORD; - else - { - register tree type_size_tree = TYPE_SIZE (type); - - if (TREE_CODE (type_size_tree) != INTEGER_CST) - return TYPE_ALIGN (type); - - return (unsigned) TREE_INT_CST_LOW (type_size_tree); - } -} - -/* Given a pointer to what is assumed to be a FIELD_DECL node, compute and - return the byte offset of the lowest addressed byte of the "containing - object" for the given FIELD_DECL, or return 0 if we are unable to - determine what that offset is, either because the argument turns out to - be a pointer to an ERROR_MARK node, or because the offset is actually - variable. (We can't handle the latter case just yet). */ - -static unsigned -field_byte_offset (decl) - register tree decl; -{ - register unsigned type_align_in_bytes; - register unsigned type_align_in_bits; - register unsigned type_size_in_bits; - register unsigned object_offset_in_align_units; - register unsigned object_offset_in_bits; - register unsigned object_offset_in_bytes; - register tree type; - register tree bitpos_tree; - register tree field_size_tree; - register unsigned bitpos_int; - register unsigned deepest_bitpos; - register unsigned field_size_in_bits; - - if (TREE_CODE (decl) == ERROR_MARK) - return 0; - - if (TREE_CODE (decl) != FIELD_DECL) - abort (); - - type = field_type (decl); - - bitpos_tree = DECL_FIELD_BITPOS (decl); - field_size_tree = DECL_SIZE (decl); - - /* We cannot yet cope with fields whose positions or sizes are variable, so - for now, when we see such things, we simply return 0. Someday, we may - be able to handle such cases, but it will be damn difficult. */ - if (TREE_CODE (bitpos_tree) != INTEGER_CST) - return 0; - bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); - - if (TREE_CODE (field_size_tree) != INTEGER_CST) - return 0; - - field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree); - type_size_in_bits = simple_type_size_in_bits (type); - type_align_in_bits = simple_type_align_in_bits (type); - type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT; - - /* Note that the GCC front-end doesn't make any attempt to keep track of - the starting bit offset (relative to the start of the containing - structure type) of the hypothetical "containing object" for a bit- - field. Thus, when computing the byte offset value for the start of the - "containing object" of a bit-field, we must deduce this information on - our own. This can be rather tricky to do in some cases. For example, - handling the following structure type definition when compiling for an - i386/i486 target (which only aligns long long's to 32-bit boundaries) - can be very tricky: - - struct S { int field1; long long field2:31; }; - - Fortunately, there is a simple rule-of-thumb which can be - used in such cases. When compiling for an i386/i486, GCC will allocate - 8 bytes for the structure shown above. It decides to do this based upon - one simple rule for bit-field allocation. Quite simply, GCC allocates - each "containing object" for each bit-field at the first (i.e. lowest - addressed) legitimate alignment boundary (based upon the required - minimum alignment for the declared type of the field) which it can - possibly use, subject to the condition that there is still enough - available space remaining in the containing object (when allocated at - the selected point) to fully accommodate all of the bits of the - bit-field itself. This simple rule makes it obvious why GCC allocates - 8 bytes for each object of the structure type shown above. When looking - for a place to allocate the "containing object" for `field2', the - compiler simply tries to allocate a 64-bit "containing object" at each - successive 32-bit boundary (starting at zero) until it finds a place to - allocate that 64- bit field such that at least 31 contiguous (and - previously unallocated) bits remain within that selected 64 bit field. - (As it turns out, for the example above, the compiler finds that it is - OK to allocate the "containing object" 64-bit field at bit-offset zero - within the structure type.) Here we attempt to work backwards from the - limited set of facts we're given, and we try to deduce from those facts, - where GCC must have believed that the containing object started (within - the structure type). The value we deduce is then used (by the callers of - this routine) to generate DW_AT_location and DW_AT_bit_offset attributes - for fields (both bit-fields and, in the case of DW_AT_location, regular - fields as well). */ - - /* Figure out the bit-distance from the start of the structure to the - "deepest" bit of the bit-field. */ - deepest_bitpos = bitpos_int + field_size_in_bits; - - /* This is the tricky part. Use some fancy footwork to deduce where the - lowest addressed bit of the containing object must be. */ - object_offset_in_bits - = ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits; - - /* Compute the offset of the containing object in "alignment units". */ - object_offset_in_align_units = object_offset_in_bits / type_align_in_bits; - - /* Compute the offset of the containing object in bytes. */ - object_offset_in_bytes = object_offset_in_align_units * type_align_in_bytes; - - return object_offset_in_bytes; -} - -/* The following routines define various Dwarf attributes and any data - associated with them. */ - -/* Add a location description attribute value to a DIE. - - This emits location attributes suitable for whole variables and - whole parameters. Note that the location attributes for struct fields are - generated by the routine `data_member_location_attribute' below. */ - -static void -add_AT_location_description (die, attr_kind, rtl) - dw_die_ref die; - enum dwarf_attribute attr_kind; - register rtx rtl; -{ - /* Handle a special case. If we are about to output a location descriptor - for a variable or parameter which has been optimized out of existence, - don't do that. A variable which has been optimized out - of existence will have a DECL_RTL value which denotes a pseudo-reg. - Currently, in some rare cases, variables can have DECL_RTL values which - look like (MEM (REG pseudo-reg#)). These cases are due to bugs - elsewhere in the compiler. We treat such cases as if the variable(s) in - question had been optimized out of existence. */ - - if (is_pseudo_reg (rtl) - || (GET_CODE (rtl) == MEM - && is_pseudo_reg (XEXP (rtl, 0))) - || (GET_CODE (rtl) == CONCAT - && is_pseudo_reg (XEXP (rtl, 0)) - && is_pseudo_reg (XEXP (rtl, 1)))) - return; - - add_AT_loc (die, attr_kind, loc_descriptor (rtl)); -} - -/* Attach the specialized form of location attribute used for data - members of struct and union types. In the special case of a - FIELD_DECL node which represents a bit-field, the "offset" part - of this special location descriptor must indicate the distance - in bytes from the lowest-addressed byte of the containing struct - or union type to the lowest-addressed byte of the "containing - object" for the bit-field. (See the `field_byte_offset' function - above).. For any given bit-field, the "containing object" is a - hypothetical object (of some integral or enum type) within which - the given bit-field lives. The type of this hypothetical - "containing object" is always the same as the declared type of - the individual bit-field itself (for GCC anyway... the DWARF - spec doesn't actually mandate this). Note that it is the size - (in bytes) of the hypothetical "containing object" which will - be given in the DW_AT_byte_size attribute for this bit-field. - (See the `byte_size_attribute' function below.) It is also used - when calculating the value of the DW_AT_bit_offset attribute. - (See the `bit_offset_attribute' function below). */ - -static void -add_data_member_location_attribute (die, decl) - register dw_die_ref die; - register tree decl; -{ - register unsigned long offset; - register dw_loc_descr_ref loc_descr; - register enum dwarf_location_atom op; - - if (TREE_CODE (decl) == TREE_VEC) - offset = TREE_INT_CST_LOW (BINFO_OFFSET (decl)); - else - offset = field_byte_offset (decl); - - /* The DWARF2 standard says that we should assume that the structure address - is already on the stack, so we can specify a structure field address - by using DW_OP_plus_uconst. */ - -#ifdef MIPS_DEBUGGING_INFO - /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst operator - correctly. It works only if we leave the offset on the stack. */ - op = DW_OP_constu; -#else - op = DW_OP_plus_uconst; -#endif - - loc_descr = new_loc_descr (op, offset, 0); - add_AT_loc (die, DW_AT_data_member_location, loc_descr); -} - -/* Attach an DW_AT_const_value attribute for a variable or a parameter which - does not have a "location" either in memory or in a register. These - things can arise in GNU C when a constant is passed as an actual parameter - to an inlined function. They can also arise in C++ where declared - constants do not necessarily get memory "homes". */ - -static void -add_const_value_attribute (die, rtl) - register dw_die_ref die; - register rtx rtl; -{ - switch (GET_CODE (rtl)) - { - case CONST_INT: - /* Note that a CONST_INT rtx could represent either an integer or a - floating-point constant. A CONST_INT is used whenever the constant - will fit into a single word. In all such cases, the original mode - of the constant value is wiped out, and the CONST_INT rtx is - assigned VOIDmode. */ - add_AT_unsigned (die, DW_AT_const_value, (unsigned) INTVAL (rtl)); - break; - - case CONST_DOUBLE: - /* Note that a CONST_DOUBLE rtx could represent either an integer or a - floating-point constant. A CONST_DOUBLE is used whenever the - constant requires more than one word in order to be adequately - represented. We output CONST_DOUBLEs as blocks. */ - { - register enum machine_mode mode = GET_MODE (rtl); - - if (GET_MODE_CLASS (mode) == MODE_FLOAT) - { - register unsigned length = GET_MODE_SIZE (mode) / sizeof (long); - long array[4]; - REAL_VALUE_TYPE rv; - - REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl); - switch (mode) - { - case SFmode: - REAL_VALUE_TO_TARGET_SINGLE (rv, array[0]); - break; - - case DFmode: - REAL_VALUE_TO_TARGET_DOUBLE (rv, array); - break; - - case XFmode: - case TFmode: - REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, array); - break; - - default: - abort (); - } - - add_AT_float (die, DW_AT_const_value, length, array); - } - else - add_AT_long_long (die, DW_AT_const_value, - CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl)); - } - break; - - case CONST_STRING: - add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0)); - break; - - case SYMBOL_REF: - case LABEL_REF: - case CONST: - add_AT_addr (die, DW_AT_const_value, addr_to_string (rtl)); - break; - - case PLUS: - /* In cases where an inlined instance of an inline function is passed - the address of an `auto' variable (which is local to the caller) we - can get a situation where the DECL_RTL of the artificial local - variable (for the inlining) which acts as a stand-in for the - corresponding formal parameter (of the inline function) will look - like (plus:SI (reg:SI FRAME_PTR) (const_int ...)). This is not - exactly a compile-time constant expression, but it isn't the address - of the (artificial) local variable either. Rather, it represents the - *value* which the artificial local variable always has during its - lifetime. We currently have no way to represent such quasi-constant - values in Dwarf, so for now we just punt and generate nothing. */ - break; - - default: - /* No other kinds of rtx should be possible here. */ - abort (); - } - -} - -/* Generate *either* an DW_AT_location attribute or else an DW_AT_const_value - data attribute for a variable or a parameter. We generate the - DW_AT_const_value attribute only in those cases where the given variable - or parameter does not have a true "location" either in memory or in a - register. This can happen (for example) when a constant is passed as an - actual argument in a call to an inline function. (It's possible that - these things can crop up in other ways also.) Note that one type of - constant value which can be passed into an inlined function is a constant - pointer. This can happen for example if an actual argument in an inlined - function call evaluates to a compile-time constant address. */ - -static void -add_location_or_const_value_attribute (die, decl) - register dw_die_ref die; - register tree decl; -{ - register rtx rtl; - register tree declared_type; - register tree passed_type; - - if (TREE_CODE (decl) == ERROR_MARK) - return; - - if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL) - abort (); - - /* Here we have to decide where we are going to say the parameter "lives" - (as far as the debugger is concerned). We only have a couple of - choices. GCC provides us with DECL_RTL and with DECL_INCOMING_RTL. - - DECL_RTL normally indicates where the parameter lives during most of the - activation of the function. If optimization is enabled however, this - could be either NULL or else a pseudo-reg. Both of those cases indicate - that the parameter doesn't really live anywhere (as far as the code - generation parts of GCC are concerned) during most of the function's - activation. That will happen (for example) if the parameter is never - referenced within the function. - - We could just generate a location descriptor here for all non-NULL - non-pseudo values of DECL_RTL and ignore all of the rest, but we can be - a little nicer than that if we also consider DECL_INCOMING_RTL in cases - where DECL_RTL is NULL or is a pseudo-reg. - - Note however that we can only get away with using DECL_INCOMING_RTL as - a backup substitute for DECL_RTL in certain limited cases. In cases - where DECL_ARG_TYPE (decl) indicates the same type as TREE_TYPE (decl), - we can be sure that the parameter was passed using the same type as it is - declared to have within the function, and that its DECL_INCOMING_RTL - points us to a place where a value of that type is passed. - - In cases where DECL_ARG_TYPE (decl) and TREE_TYPE (decl) are different, - we cannot (in general) use DECL_INCOMING_RTL as a substitute for DECL_RTL - because in these cases DECL_INCOMING_RTL points us to a value of some - type which is *different* from the type of the parameter itself. Thus, - if we tried to use DECL_INCOMING_RTL to generate a location attribute in - such cases, the debugger would end up (for example) trying to fetch a - `float' from a place which actually contains the first part of a - `double'. That would lead to really incorrect and confusing - output at debug-time. - - So, in general, we *do not* use DECL_INCOMING_RTL as a backup for DECL_RTL - in cases where DECL_ARG_TYPE (decl) != TREE_TYPE (decl). There - are a couple of exceptions however. On little-endian machines we can - get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE (decl) is - not the same as TREE_TYPE (decl), but only when DECL_ARG_TYPE (decl) is - an integral type that is smaller than TREE_TYPE (decl). These cases arise - when (on a little-endian machine) a non-prototyped function has a - parameter declared to be of type `short' or `char'. In such cases, - TREE_TYPE (decl) will be `short' or `char', DECL_ARG_TYPE (decl) will - be `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the - passed `int' value. If the debugger then uses that address to fetch - a `short' or a `char' (on a little-endian machine) the result will be - the correct data, so we allow for such exceptional cases below. - - Note that our goal here is to describe the place where the given formal - parameter lives during most of the function's activation (i.e. between - the end of the prologue and the start of the epilogue). We'll do that - as best as we can. Note however that if the given formal parameter is - modified sometime during the execution of the function, then a stack - backtrace (at debug-time) will show the function as having been - called with the *new* value rather than the value which was - originally passed in. This happens rarely enough that it is not - a major problem, but it *is* a problem, and I'd like to fix it. - - A future version of dwarf2out.c may generate two additional - attributes for any given DW_TAG_formal_parameter DIE which will - describe the "passed type" and the "passed location" for the - given formal parameter in addition to the attributes we now - generate to indicate the "declared type" and the "active - location" for each parameter. This additional set of attributes - could be used by debuggers for stack backtraces. Separately, note - that sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL can be - NULL also. This happens (for example) for inlined-instances of - inline function formal parameters which are never referenced. - This really shouldn't be happening. All PARM_DECL nodes should - get valid non-NULL DECL_INCOMING_RTL values, but integrate.c - doesn't currently generate these values for inlined instances of - inline function parameters, so when we see such cases, we are - just out-of-luck for the time being (until integrate.c - gets fixed). */ - - /* Use DECL_RTL as the "location" unless we find something better. */ - rtl = DECL_RTL (decl); - - if (TREE_CODE (decl) == PARM_DECL) - { - if (rtl == NULL_RTX || is_pseudo_reg (rtl)) - { - declared_type = type_main_variant (TREE_TYPE (decl)); - passed_type = type_main_variant (DECL_ARG_TYPE (decl)); - - /* This decl represents a formal parameter which was optimized out. - Note that DECL_INCOMING_RTL may be NULL in here, but we handle - all* cases where (rtl == NULL_RTX) just below. */ - if (declared_type == passed_type) - rtl = DECL_INCOMING_RTL (decl); - else if (! BYTES_BIG_ENDIAN - && TREE_CODE (declared_type) == INTEGER_TYPE - && (GET_MODE_SIZE (TYPE_MODE (declared_type)) - <= GET_MODE_SIZE (TYPE_MODE (passed_type)))) - rtl = DECL_INCOMING_RTL (decl); - } - - /* If the parm was passed in registers, but lives on the stack, then - make a big endian correction if the mode of the type of the - parameter is not the same as the mode of the rtl. */ - /* ??? This is the same series of checks that are made in dbxout.c before - we reach the big endian correction code there. It isn't clear if all - of these checks are necessary here, but keeping them all is the safe - thing to do. */ - else if (GET_CODE (rtl) == MEM - && XEXP (rtl, 0) != const0_rtx - && ! CONSTANT_P (XEXP (rtl, 0)) - /* Not passed in memory. */ - && GET_CODE (DECL_INCOMING_RTL (decl)) != MEM - /* Not passed by invisible reference. */ - && (GET_CODE (XEXP (rtl, 0)) != REG - || REGNO (XEXP (rtl, 0)) == HARD_FRAME_POINTER_REGNUM - || REGNO (XEXP (rtl, 0)) == STACK_POINTER_REGNUM -#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM - || REGNO (XEXP (rtl, 0)) == ARG_POINTER_REGNUM -#endif - ) - /* Big endian correction check. */ - && BYTES_BIG_ENDIAN - && TYPE_MODE (TREE_TYPE (decl)) != GET_MODE (rtl) - && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl))) - < UNITS_PER_WORD)) - { - int offset = (UNITS_PER_WORD - - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)))); - rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)), - plus_constant (XEXP (rtl, 0), offset)); - } - } - - if (rtl == NULL_RTX) - return; - - rtl = eliminate_regs (rtl, 0, NULL_RTX); -#ifdef LEAF_REG_REMAP - if (current_function_uses_only_leaf_regs) - leaf_renumber_regs_insn (rtl); -#endif - - switch (GET_CODE (rtl)) - { - case ADDRESSOF: - /* The address of a variable that was optimized away; don't emit - anything. */ - break; - - case CONST_INT: - case CONST_DOUBLE: - case CONST_STRING: - case SYMBOL_REF: - case LABEL_REF: - case CONST: - case PLUS: - /* DECL_RTL could be (plus (reg ...) (const_int ...)) */ - add_const_value_attribute (die, rtl); - break; - - case MEM: - case REG: - case SUBREG: - case CONCAT: - add_AT_location_description (die, DW_AT_location, rtl); - break; - - default: - abort (); - } -} - -/* Generate an DW_AT_name attribute given some string value to be included as - the value of the attribute. */ - -static inline void -add_name_attribute (die, name_string) - register dw_die_ref die; - register char *name_string; -{ - if (name_string != NULL && *name_string != 0) - add_AT_string (die, DW_AT_name, name_string); -} - -/* Given a tree node describing an array bound (either lower or upper) output - a representation for that bound. */ - -static void -add_bound_info (subrange_die, bound_attr, bound) - register dw_die_ref subrange_die; - register enum dwarf_attribute bound_attr; - register tree bound; -{ - register unsigned bound_value = 0; - - /* If this is an Ada unconstrained array type, then don't emit any debug - info because the array bounds are unknown. They are parameterized when - the type is instantiated. */ - if (contains_placeholder_p (bound)) - return; - - switch (TREE_CODE (bound)) - { - case ERROR_MARK: - return; - - /* All fixed-bounds are represented by INTEGER_CST nodes. */ - case INTEGER_CST: - bound_value = TREE_INT_CST_LOW (bound); - if (bound_attr == DW_AT_lower_bound - && ((is_c_family () && bound_value == 0) - || (is_fortran () && bound_value == 1))) - /* use the default */; - else - add_AT_unsigned (subrange_die, bound_attr, bound_value); - break; - - case CONVERT_EXPR: - case NOP_EXPR: - case NON_LVALUE_EXPR: - add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0)); - break; - - case SAVE_EXPR: - /* If optimization is turned on, the SAVE_EXPRs that describe how to - access the upper bound values may be bogus. If they refer to a - register, they may only describe how to get at these values at the - points in the generated code right after they have just been - computed. Worse yet, in the typical case, the upper bound values - will not even *be* computed in the optimized code (though the - number of elements will), so these SAVE_EXPRs are entirely - bogus. In order to compensate for this fact, we check here to see - if optimization is enabled, and if so, we don't add an attribute - for the (unknown and unknowable) upper bound. This should not - cause too much trouble for existing (stupid?) debuggers because - they have to deal with empty upper bounds location descriptions - anyway in order to be able to deal with incomplete array types. - Of course an intelligent debugger (GDB?) should be able to - comprehend that a missing upper bound specification in a array - type used for a storage class `auto' local array variable - indicates that the upper bound is both unknown (at compile- time) - and unknowable (at run-time) due to optimization. - - We assume that a MEM rtx is safe because gcc wouldn't put the - value there unless it was going to be used repeatedly in the - function, i.e. for cleanups. */ - if (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM) - { - register dw_die_ref ctx = lookup_decl_die (current_function_decl); - register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx); - register rtx loc = SAVE_EXPR_RTL (bound); - - /* If the RTL for the SAVE_EXPR is memory, handle the case where - it references an outer function's frame. */ - - if (GET_CODE (loc) == MEM) - { - rtx new_addr = fix_lexical_addr (XEXP (loc, 0), bound); - - if (XEXP (loc, 0) != new_addr) - loc = gen_rtx (MEM, GET_MODE (loc), new_addr); - } - - add_AT_flag (decl_die, DW_AT_artificial, 1); - add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx); - add_AT_location_description (decl_die, DW_AT_location, loc); - add_AT_die_ref (subrange_die, bound_attr, decl_die); - } - - /* Else leave out the attribute. */ - break; - - case MAX_EXPR: - case VAR_DECL: - case COMPONENT_REF: - /* ??? These types of bounds can be created by the Ada front end, - and it isn't clear how to emit debug info for them. */ - break; - - default: - abort (); - } -} - -/* Note that the block of subscript information for an array type also - includes information about the element type of type given array type. */ - -static void -add_subscript_info (type_die, type) - register dw_die_ref type_die; - register tree type; -{ -#ifndef MIPS_DEBUGGING_INFO - register unsigned dimension_number; -#endif - register tree lower, upper; - register dw_die_ref subrange_die; - - /* The GNU compilers represent multidimensional array types as sequences of - one dimensional array types whose element types are themselves array - types. Here we squish that down, so that each multidimensional array - type gets only one array_type DIE in the Dwarf debugging info. The draft - Dwarf specification say that we are allowed to do this kind of - compression in C (because there is no difference between an array or - arrays and a multidimensional array in C) but for other source languages - (e.g. Ada) we probably shouldn't do this. */ - - /* ??? The SGI dwarf reader fails for multidimensional arrays with a - const enum type. E.g. const enum machine_mode insn_operand_mode[2][10]. - We work around this by disabling this feature. See also - gen_array_type_die. */ -#ifndef MIPS_DEBUGGING_INFO - for (dimension_number = 0; - TREE_CODE (type) == ARRAY_TYPE; - type = TREE_TYPE (type), dimension_number++) - { -#endif - register tree domain = TYPE_DOMAIN (type); - - /* Arrays come in three flavors: Unspecified bounds, fixed bounds, - and (in GNU C only) variable bounds. Handle all three forms - here. */ - subrange_die = new_die (DW_TAG_subrange_type, type_die); - if (domain) - { - /* We have an array type with specified bounds. */ - lower = TYPE_MIN_VALUE (domain); - upper = TYPE_MAX_VALUE (domain); - - /* define the index type. */ - if (TREE_TYPE (domain)) - { - /* ??? This is probably an Ada unnamed subrange type. Ignore the - TREE_TYPE field. We can't emit debug info for this - because it is an unnamed integral type. */ - if (TREE_CODE (domain) == INTEGER_TYPE - && TYPE_NAME (domain) == NULL_TREE - && TREE_CODE (TREE_TYPE (domain)) == INTEGER_TYPE - && TYPE_NAME (TREE_TYPE (domain)) == NULL_TREE) - ; - else - add_type_attribute (subrange_die, TREE_TYPE (domain), 0, 0, - type_die); - } - - /* ??? If upper is NULL, the array has unspecified length, - but it does have a lower bound. This happens with Fortran - dimension arr(N:*) - Since the debugger is definitely going to need to know N - to produce useful results, go ahead and output the lower - bound solo, and hope the debugger can cope. */ - - add_bound_info (subrange_die, DW_AT_lower_bound, lower); - if (upper) - add_bound_info (subrange_die, DW_AT_upper_bound, upper); - } - else - /* We have an array type with an unspecified length. The DWARF-2 - spec does not say how to handle this; let's just leave out the - bounds. */ - {;} - - -#ifndef MIPS_DEBUGGING_INFO - } -#endif -} - -static void -add_byte_size_attribute (die, tree_node) - dw_die_ref die; - register tree tree_node; -{ - register unsigned size; - - switch (TREE_CODE (tree_node)) - { - case ERROR_MARK: - size = 0; - break; - case ENUMERAL_TYPE: - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - size = int_size_in_bytes (tree_node); - break; - case FIELD_DECL: - /* For a data member of a struct or union, the DW_AT_byte_size is - generally given as the number of bytes normally allocated for an - object of the *declared* type of the member itself. This is true - even for bit-fields. */ - size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT; - break; - default: - abort (); - } - - /* Note that `size' might be -1 when we get to this point. If it is, that - indicates that the byte size of the entity in question is variable. We - have no good way of expressing this fact in Dwarf at the present time, - so just let the -1 pass on through. */ - - add_AT_unsigned (die, DW_AT_byte_size, size); -} - -/* For a FIELD_DECL node which represents a bit-field, output an attribute - which specifies the distance in bits from the highest order bit of the - "containing object" for the bit-field to the highest order bit of the - bit-field itself. - - For any given bit-field, the "containing object" is a hypothetical - object (of some integral or enum type) within which the given bit-field - lives. The type of this hypothetical "containing object" is always the - same as the declared type of the individual bit-field itself. The - determination of the exact location of the "containing object" for a - bit-field is rather complicated. It's handled by the - `field_byte_offset' function (above). - - Note that it is the size (in bytes) of the hypothetical "containing object" - which will be given in the DW_AT_byte_size attribute for this bit-field. - (See `byte_size_attribute' above). */ - -static inline void -add_bit_offset_attribute (die, decl) - register dw_die_ref die; - register tree decl; -{ - register unsigned object_offset_in_bytes = field_byte_offset (decl); - register tree type = DECL_BIT_FIELD_TYPE (decl); - register tree bitpos_tree = DECL_FIELD_BITPOS (decl); - register unsigned bitpos_int; - register unsigned highest_order_object_bit_offset; - register unsigned highest_order_field_bit_offset; - register unsigned bit_offset; - - /* Must be a field and a bit field. */ - if (!type - || TREE_CODE (decl) != FIELD_DECL) - abort (); - - /* We can't yet handle bit-fields whose offsets are variable, so if we - encounter such things, just return without generating any attribute - whatsoever. */ - if (TREE_CODE (bitpos_tree) != INTEGER_CST) - return; - - bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree); - - /* Note that the bit offset is always the distance (in bits) from the - highest-order bit of the "containing object" to the highest-order bit of - the bit-field itself. Since the "high-order end" of any object or field - is different on big-endian and little-endian machines, the computation - below must take account of these differences. */ - highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT; - highest_order_field_bit_offset = bitpos_int; - - if (! BYTES_BIG_ENDIAN) - { - highest_order_field_bit_offset - += (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl)); - - highest_order_object_bit_offset += simple_type_size_in_bits (type); - } - - bit_offset - = (! BYTES_BIG_ENDIAN - ? highest_order_object_bit_offset - highest_order_field_bit_offset - : highest_order_field_bit_offset - highest_order_object_bit_offset); - - add_AT_unsigned (die, DW_AT_bit_offset, bit_offset); -} - -/* For a FIELD_DECL node which represents a bit field, output an attribute - which specifies the length in bits of the given field. */ - -static inline void -add_bit_size_attribute (die, decl) - register dw_die_ref die; - register tree decl; -{ - /* Must be a field and a bit field. */ - if (TREE_CODE (decl) != FIELD_DECL - || ! DECL_BIT_FIELD_TYPE (decl)) - abort (); - add_AT_unsigned (die, DW_AT_bit_size, - (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl))); -} - -/* If the compiled language is ANSI C, then add a 'prototyped' - attribute, if arg types are given for the parameters of a function. */ - -static inline void -add_prototyped_attribute (die, func_type) - register dw_die_ref die; - register tree func_type; -{ - if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89 - && TYPE_ARG_TYPES (func_type) != NULL) - add_AT_flag (die, DW_AT_prototyped, 1); -} - - -/* Add an 'abstract_origin' attribute below a given DIE. The DIE is found - by looking in either the type declaration or object declaration - equate table. */ - -static inline void -add_abstract_origin_attribute (die, origin) - register dw_die_ref die; - register tree origin; -{ - dw_die_ref origin_die = NULL; - if (TREE_CODE_CLASS (TREE_CODE (origin)) == 'd') - origin_die = lookup_decl_die (origin); - else if (TREE_CODE_CLASS (TREE_CODE (origin)) == 't') - origin_die = lookup_type_die (origin); - - add_AT_die_ref (die, DW_AT_abstract_origin, origin_die); -} - -/* We do not currently support the pure_virtual attribute. */ - -static inline void -add_pure_or_virtual_attribute (die, func_decl) - register dw_die_ref die; - register tree func_decl; -{ - if (DECL_VINDEX (func_decl)) - { - add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual); - add_AT_loc (die, DW_AT_vtable_elem_location, - new_loc_descr (DW_OP_constu, - TREE_INT_CST_LOW (DECL_VINDEX (func_decl)), - 0)); - - /* GNU extension: Record what type this method came from originally. */ - if (debug_info_level > DINFO_LEVEL_TERSE) - add_AT_die_ref (die, DW_AT_containing_type, - lookup_type_die (DECL_CONTEXT (func_decl))); - } -} - -/* Add source coordinate attributes for the given decl. */ - -static void -add_src_coords_attributes (die, decl) - register dw_die_ref die; - register tree decl; -{ - register unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl)); - - add_AT_unsigned (die, DW_AT_decl_file, file_index); - add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl)); -} - -/* Add an DW_AT_name attribute and source coordinate attribute for the - given decl, but only if it actually has a name. */ - -static void -add_name_and_src_coords_attributes (die, decl) - register dw_die_ref die; - register tree decl; -{ - register tree decl_name; - - decl_name = DECL_NAME (decl); - if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL) - { - add_name_attribute (die, dwarf2_name (decl, 0)); - add_src_coords_attributes (die, decl); - if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) - && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) - add_AT_string (die, DW_AT_MIPS_linkage_name, - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); - } -} - -/* Push a new declaration scope. */ - -static void -push_decl_scope (scope) - tree scope; -{ - tree containing_scope; - int i; - - /* Make room in the decl_scope_table, if necessary. */ - if (decl_scope_table_allocated == decl_scope_depth) - { - decl_scope_table_allocated += DECL_SCOPE_TABLE_INCREMENT; - decl_scope_table - = (decl_scope_node *) xrealloc (decl_scope_table, - (decl_scope_table_allocated - * sizeof (decl_scope_node))); - } - - decl_scope_table[decl_scope_depth].scope = scope; - - /* Sometimes, while recursively emitting subtypes within a class type, - we end up recuring on a subtype at a higher level then the current - subtype. In such a case, we need to search the decl_scope_table to - find the parent of this subtype. */ - - if (AGGREGATE_TYPE_P (scope)) - containing_scope = TYPE_CONTEXT (scope); - else - containing_scope = NULL_TREE; - - /* The normal case. */ - if (decl_scope_depth == 0 - || containing_scope == NULL_TREE - /* Ignore namespaces for the moment. */ - || TREE_CODE (containing_scope) == NAMESPACE_DECL - || containing_scope == decl_scope_table[decl_scope_depth - 1].scope) - decl_scope_table[decl_scope_depth].previous = decl_scope_depth - 1; - else - { - /* We need to search for the containing_scope. */ - for (i = 0; i < decl_scope_depth; i++) - if (decl_scope_table[i].scope == containing_scope) - break; - - if (i == decl_scope_depth) - abort (); - else - decl_scope_table[decl_scope_depth].previous = i; - } - - decl_scope_depth++; -} - -/* Return the DIE for the scope that immediately contains this declaration. */ - -static dw_die_ref -scope_die_for (t, context_die) - register tree t; - register dw_die_ref context_die; -{ - register dw_die_ref scope_die = NULL; - register tree containing_scope; - register int i; - - /* Walk back up the declaration tree looking for a place to define - this type. */ - if (TREE_CODE_CLASS (TREE_CODE (t)) == 't') - containing_scope = TYPE_CONTEXT (t); - else if (TREE_CODE (t) == FUNCTION_DECL && DECL_VINDEX (t)) - containing_scope = decl_class_context (t); - else - containing_scope = DECL_CONTEXT (t); - - /* Ignore namespaces for the moment. */ - if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL) - containing_scope = NULL_TREE; - - /* Ignore function type "scopes" from the C frontend. They mean that - a tagged type is local to a parmlist of a function declarator, but - that isn't useful to DWARF. */ - if (containing_scope && TREE_CODE (containing_scope) == FUNCTION_TYPE) - containing_scope = NULL_TREE; - - /* Function-local tags and functions get stuck in limbo until they are - fixed up by decls_for_scope. */ - if (context_die == NULL && containing_scope != NULL_TREE - && (TREE_CODE (t) == FUNCTION_DECL || is_tagged_type (t))) - return NULL; - - if (containing_scope == NULL_TREE) - scope_die = comp_unit_die; - else - { - for (i = decl_scope_depth - 1, scope_die = context_die; - i >= 0 && decl_scope_table[i].scope != containing_scope; - (scope_die = scope_die->die_parent, - i = decl_scope_table[i].previous)) - ; - - /* ??? Integrate_decl_tree does not handle BLOCK_TYPE_TAGS, nor - does it try to handle types defined by TYPE_DECLs. Such types - thus have an incorrect TYPE_CONTEXT, which points to the block - they were originally defined in, instead of the current block - created by function inlining. We try to detect that here and - work around it. */ - - if (i < 0 && scope_die == comp_unit_die - && TREE_CODE (containing_scope) == BLOCK - && is_tagged_type (t) - && (block_ultimate_origin (decl_scope_table[decl_scope_depth - 1].scope) - == containing_scope)) - { - scope_die = context_die; - /* Since the checks below are no longer applicable. */ - i = 0; - } - - if (i < 0) - { - if (TREE_CODE_CLASS (TREE_CODE (containing_scope)) != 't') - abort (); - if (debug_info_level > DINFO_LEVEL_TERSE - && !TREE_ASM_WRITTEN (containing_scope)) - abort (); - - /* If none of the current dies are suitable, we get file scope. */ - scope_die = comp_unit_die; - } - } - - return scope_die; -} - -/* Pop a declaration scope. */ -static inline void -pop_decl_scope () -{ - if (decl_scope_depth <= 0) - abort (); - --decl_scope_depth; -} - -/* Many forms of DIEs require a "type description" attribute. This - routine locates the proper "type descriptor" die for the type given - by 'type', and adds an DW_AT_type attribute below the given die. */ - -static void -add_type_attribute (object_die, type, decl_const, decl_volatile, context_die) - register dw_die_ref object_die; - register tree type; - register int decl_const; - register int decl_volatile; - register dw_die_ref context_die; -{ - register enum tree_code code = TREE_CODE (type); - register dw_die_ref type_die = NULL; - - /* ??? If this type is an unnamed subrange type of an integral or - floating-point type, use the inner type. This is because we have no - support for unnamed types in base_type_die. This can happen if this is - an Ada subrange type. Correct solution is emit a subrange type die. */ - if ((code == INTEGER_TYPE || code == REAL_TYPE) - && TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0) - type = TREE_TYPE (type), code = TREE_CODE (type); - - if (code == ERROR_MARK) - return; - - /* Handle a special case. For functions whose return type is void, we - generate *no* type attribute. (Note that no object may have type - `void', so this only applies to function return types). */ - if (code == VOID_TYPE) - return; - - type_die = modified_type_die (type, - decl_const || TYPE_READONLY (type), - decl_volatile || TYPE_VOLATILE (type), - context_die); - if (type_die != NULL) - add_AT_die_ref (object_die, DW_AT_type, type_die); -} - -/* Given a tree pointer to a struct, class, union, or enum type node, return - a pointer to the (string) tag name for the given type, or zero if the type - was declared without a tag. */ - -static char * -type_tag (type) - register tree type; -{ - register char *name = 0; - - if (TYPE_NAME (type) != 0) - { - register tree t = 0; - - /* Find the IDENTIFIER_NODE for the type name. */ - if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) - t = TYPE_NAME (type); - - /* The g++ front end makes the TYPE_NAME of *each* tagged type point to - a TYPE_DECL node, regardless of whether or not a `typedef' was - involved. */ - else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && ! DECL_IGNORED_P (TYPE_NAME (type))) - t = DECL_NAME (TYPE_NAME (type)); - - /* Now get the name as a string, or invent one. */ - if (t != 0) - name = IDENTIFIER_POINTER (t); - } - - return (name == 0 || *name == '\0') ? 0 : name; -} - -/* Return the type associated with a data member, make a special check - for bit field types. */ - -static inline tree -member_declared_type (member) - register tree member; -{ - return (DECL_BIT_FIELD_TYPE (member) - ? DECL_BIT_FIELD_TYPE (member) - : TREE_TYPE (member)); -} - -/* Get the decl's label, as described by its RTL. This may be different - from the DECL_NAME name used in the source file. */ - -#if 0 -static char * -decl_start_label (decl) - register tree decl; -{ - rtx x; - char *fnname; - x = DECL_RTL (decl); - if (GET_CODE (x) != MEM) - abort (); - - x = XEXP (x, 0); - if (GET_CODE (x) != SYMBOL_REF) - abort (); - - fnname = XSTR (x, 0); - return fnname; -} -#endif - -/* These routines generate the internal representation of the DIE's for - the compilation unit. Debugging information is collected by walking - the declaration trees passed in from dwarf2out_decl(). */ - -static void -gen_array_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref scope_die = scope_die_for (type, context_die); - register dw_die_ref array_die; - register tree element_type; - - /* ??? The SGI dwarf reader fails for array of array of enum types unless - the inner array type comes before the outer array type. Thus we must - call gen_type_die before we call new_die. See below also. */ -#ifdef MIPS_DEBUGGING_INFO - gen_type_die (TREE_TYPE (type), context_die); -#endif - - array_die = new_die (DW_TAG_array_type, scope_die); - -#if 0 - /* We default the array ordering. SDB will probably do - the right things even if DW_AT_ordering is not present. It's not even - an issue until we start to get into multidimensional arrays anyway. If - SDB is ever caught doing the Wrong Thing for multi-dimensional arrays, - then we'll have to put the DW_AT_ordering attribute back in. (But if - and when we find out that we need to put these in, we will only do so - for multidimensional arrays. */ - add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major); -#endif - -#ifdef MIPS_DEBUGGING_INFO - /* The SGI compilers handle arrays of unknown bound by setting - AT_declaration and not emitting any subrange DIEs. */ - if (! TYPE_DOMAIN (type)) - add_AT_unsigned (array_die, DW_AT_declaration, 1); - else -#endif - add_subscript_info (array_die, type); - - equate_type_number_to_die (type, array_die); - - /* Add representation of the type of the elements of this array type. */ - element_type = TREE_TYPE (type); - - /* ??? The SGI dwarf reader fails for multidimensional arrays with a - const enum type. E.g. const enum machine_mode insn_operand_mode[2][10]. - We work around this by disabling this feature. See also - add_subscript_info. */ -#ifndef MIPS_DEBUGGING_INFO - while (TREE_CODE (element_type) == ARRAY_TYPE) - element_type = TREE_TYPE (element_type); - - gen_type_die (element_type, context_die); -#endif - - add_type_attribute (array_die, element_type, 0, 0, context_die); -} - -static void -gen_set_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref type_die - = new_die (DW_TAG_set_type, scope_die_for (type, context_die)); - - equate_type_number_to_die (type, type_die); - add_type_attribute (type_die, TREE_TYPE (type), 0, 0, context_die); -} - -#if 0 -static void -gen_entry_point_die (decl, context_die) - register tree decl; - register dw_die_ref context_die; -{ - register tree origin = decl_ultimate_origin (decl); - register dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die); - if (origin != NULL) - add_abstract_origin_attribute (decl_die, origin); - else - { - add_name_and_src_coords_attributes (decl_die, decl); - add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)), - 0, 0, context_die); - } - - if (DECL_ABSTRACT (decl)) - equate_decl_number_to_die (decl, decl_die); - else - add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl)); -} -#endif - -/* Remember a type in the pending_types_list. */ - -static void -pend_type (type) - register tree type; -{ - if (pending_types == pending_types_allocated) - { - pending_types_allocated += PENDING_TYPES_INCREMENT; - pending_types_list - = (tree *) xrealloc (pending_types_list, - sizeof (tree) * pending_types_allocated); - } - - pending_types_list[pending_types++] = type; -} - -/* Output any pending types (from the pending_types list) which we can output - now (taking into account the scope that we are working on now). - - For each type output, remove the given type from the pending_types_list - *before* we try to output it. */ - -static void -output_pending_types_for_scope (context_die) - register dw_die_ref context_die; -{ - register tree type; - - while (pending_types) - { - --pending_types; - type = pending_types_list[pending_types]; - gen_type_die (type, context_die); - if (!TREE_ASM_WRITTEN (type)) - abort (); - } -} - -/* Remember a type in the incomplete_types_list. */ - -static void -add_incomplete_type (type) - tree type; -{ - if (incomplete_types == incomplete_types_allocated) - { - incomplete_types_allocated += INCOMPLETE_TYPES_INCREMENT; - incomplete_types_list - = (tree *) xrealloc (incomplete_types_list, - sizeof (tree) * incomplete_types_allocated); - } - - incomplete_types_list[incomplete_types++] = type; -} - -/* Walk through the list of incomplete types again, trying once more to - emit full debugging info for them. */ - -static void -retry_incomplete_types () -{ - register tree type; - - while (incomplete_types) - { - --incomplete_types; - type = incomplete_types_list[incomplete_types]; - gen_type_die (type, comp_unit_die); - } -} - -/* Generate a DIE to represent an inlined instance of an enumeration type. */ - -static void -gen_inlined_enumeration_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref type_die = new_die (DW_TAG_enumeration_type, - scope_die_for (type, context_die)); - - if (!TREE_ASM_WRITTEN (type)) - abort (); - add_abstract_origin_attribute (type_die, type); -} - -/* Generate a DIE to represent an inlined instance of a structure type. */ - -static void -gen_inlined_structure_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref type_die = new_die (DW_TAG_structure_type, - scope_die_for (type, context_die)); - - if (!TREE_ASM_WRITTEN (type)) - abort (); - add_abstract_origin_attribute (type_die, type); -} - -/* Generate a DIE to represent an inlined instance of a union type. */ - -static void -gen_inlined_union_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref type_die = new_die (DW_TAG_union_type, - scope_die_for (type, context_die)); - - if (!TREE_ASM_WRITTEN (type)) - abort (); - add_abstract_origin_attribute (type_die, type); -} - -/* Generate a DIE to represent an enumeration type. Note that these DIEs - include all of the information about the enumeration values also. Each - enumerated type name/value is listed as a child of the enumerated type - DIE. */ - -static void -gen_enumeration_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref type_die = lookup_type_die (type); - - if (type_die == NULL) - { - type_die = new_die (DW_TAG_enumeration_type, - scope_die_for (type, context_die)); - equate_type_number_to_die (type, type_die); - add_name_attribute (type_die, type_tag (type)); - } - else if (! TYPE_SIZE (type)) - return; - else - remove_AT (type_die, DW_AT_declaration); - - /* Handle a GNU C/C++ extension, i.e. incomplete enum types. If the - given enum type is incomplete, do not generate the DW_AT_byte_size - attribute or the DW_AT_element_list attribute. */ - if (TYPE_SIZE (type)) - { - register tree link; - - TREE_ASM_WRITTEN (type) = 1; - add_byte_size_attribute (type_die, type); - if (TYPE_STUB_DECL (type) != NULL_TREE) - add_src_coords_attributes (type_die, TYPE_STUB_DECL (type)); - - /* If the first reference to this type was as the return type of an - inline function, then it may not have a parent. Fix this now. */ - if (type_die->die_parent == NULL) - add_child_die (scope_die_for (type, context_die), type_die); - - for (link = TYPE_FIELDS (type); - link != NULL; link = TREE_CHAIN (link)) - { - register dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die); - - add_name_attribute (enum_die, - IDENTIFIER_POINTER (TREE_PURPOSE (link))); - add_AT_unsigned (enum_die, DW_AT_const_value, - (unsigned) TREE_INT_CST_LOW (TREE_VALUE (link))); - } - } - else - add_AT_flag (type_die, DW_AT_declaration, 1); -} - - -/* Generate a DIE to represent either a real live formal parameter decl or to - represent just the type of some formal parameter position in some function - type. - - Note that this routine is a bit unusual because its argument may be a - ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which - represents an inlining of some PARM_DECL) or else some sort of a ..._TYPE - node. If it's the former then this function is being called to output a - DIE to represent a formal parameter object (or some inlining thereof). If - it's the latter, then this function is only being called to output a - DW_TAG_formal_parameter DIE to stand as a placeholder for some formal - argument type of some subprogram type. */ - -static dw_die_ref -gen_formal_parameter_die (node, context_die) - register tree node; - register dw_die_ref context_die; -{ - register dw_die_ref parm_die - = new_die (DW_TAG_formal_parameter, context_die); - register tree origin; - - switch (TREE_CODE_CLASS (TREE_CODE (node))) - { - case 'd': - origin = decl_ultimate_origin (node); - if (origin != NULL) - add_abstract_origin_attribute (parm_die, origin); - else - { - add_name_and_src_coords_attributes (parm_die, node); - add_type_attribute (parm_die, TREE_TYPE (node), - TREE_READONLY (node), - TREE_THIS_VOLATILE (node), - context_die); - if (DECL_ARTIFICIAL (node)) - add_AT_flag (parm_die, DW_AT_artificial, 1); - } - - equate_decl_number_to_die (node, parm_die); - if (! DECL_ABSTRACT (node)) - add_location_or_const_value_attribute (parm_die, node); - - break; - - case 't': - /* We were called with some kind of a ..._TYPE node. */ - add_type_attribute (parm_die, node, 0, 0, context_die); - break; - - default: - abort (); - } - - return parm_die; -} - -/* Generate a special type of DIE used as a stand-in for a trailing ellipsis - at the end of an (ANSI prototyped) formal parameters list. */ - -static void -gen_unspecified_parameters_die (decl_or_type, context_die) - register tree decl_or_type; - register dw_die_ref context_die; -{ - new_die (DW_TAG_unspecified_parameters, context_die); -} - -/* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a - DW_TAG_unspecified_parameters DIE) to represent the types of the formal - parameters as specified in some function type specification (except for - those which appear as part of a function *definition*). - - Note we must be careful here to output all of the parameter DIEs before* - we output any DIEs needed to represent the types of the formal parameters. - This keeps svr4 SDB happy because it (incorrectly) thinks that the first - non-parameter DIE it sees ends the formal parameter list. */ - -static void -gen_formal_types_die (function_or_method_type, context_die) - register tree function_or_method_type; - register dw_die_ref context_die; -{ - register tree link; - register tree formal_type = NULL; - register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type); - -#if 0 - /* In the case where we are generating a formal types list for a C++ - non-static member function type, skip over the first thing on the - TYPE_ARG_TYPES list because it only represents the type of the hidden - `this pointer'. The debugger should be able to figure out (without - being explicitly told) that this non-static member function type takes a - `this pointer' and should be able to figure what the type of that hidden - parameter is from the DW_AT_member attribute of the parent - DW_TAG_subroutine_type DIE. */ - if (TREE_CODE (function_or_method_type) == METHOD_TYPE) - first_parm_type = TREE_CHAIN (first_parm_type); -#endif - - /* Make our first pass over the list of formal parameter types and output a - DW_TAG_formal_parameter DIE for each one. */ - for (link = first_parm_type; link; link = TREE_CHAIN (link)) - { - register dw_die_ref parm_die; - - formal_type = TREE_VALUE (link); - if (formal_type == void_type_node) - break; - - /* Output a (nameless) DIE to represent the formal parameter itself. */ - parm_die = gen_formal_parameter_die (formal_type, context_die); - if (TREE_CODE (function_or_method_type) == METHOD_TYPE - && link == first_parm_type) - add_AT_flag (parm_die, DW_AT_artificial, 1); - } - - /* If this function type has an ellipsis, add a - DW_TAG_unspecified_parameters DIE to the end of the parameter list. */ - if (formal_type != void_type_node) - gen_unspecified_parameters_die (function_or_method_type, context_die); - - /* Make our second (and final) pass over the list of formal parameter types - and output DIEs to represent those types (as necessary). */ - for (link = TYPE_ARG_TYPES (function_or_method_type); - link; - link = TREE_CHAIN (link)) - { - formal_type = TREE_VALUE (link); - if (formal_type == void_type_node) - break; - - gen_type_die (formal_type, context_die); - } -} - -/* Generate a DIE to represent a declared function (either file-scope or - block-local). */ - -static void -gen_subprogram_die (decl, context_die) - register tree decl; - register dw_die_ref context_die; -{ - char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; - register tree origin = decl_ultimate_origin (decl); - register dw_die_ref subr_die; - register rtx fp_reg; - register tree fn_arg_types; - register tree outer_scope; - register dw_die_ref old_die = lookup_decl_die (decl); - register int declaration - = (current_function_decl != decl - || (context_die - && (context_die->die_tag == DW_TAG_structure_type - || context_die->die_tag == DW_TAG_union_type))); - - if (origin != NULL) - { - subr_die = new_die (DW_TAG_subprogram, context_die); - add_abstract_origin_attribute (subr_die, origin); - } - else if (old_die && DECL_ABSTRACT (decl) - && get_AT_unsigned (old_die, DW_AT_inline)) - { - /* This must be a redefinition of an extern inline function. - We can just reuse the old die here. */ - subr_die = old_die; - - /* Clear out the inlined attribute and parm types. */ - remove_AT (subr_die, DW_AT_inline); - remove_children (subr_die); - } - else if (old_die) - { - register unsigned file_index - = lookup_filename (DECL_SOURCE_FILE (decl)); - - if (get_AT_flag (old_die, DW_AT_declaration) != 1) - { - /* ??? This can happen if there is a bug in the program, for - instance, if it has duplicate function definitions. Ideally, - we should detect this case and ignore it. For now, if we have - already reported an error, any error at all, then assume that - we got here because of a input error, not a dwarf2 bug. */ - extern int errorcount; - if (errorcount) - return; - abort (); - } - - /* If the definition comes from the same place as the declaration, - maybe use the old DIE. We always want the DIE for this function - that has the *_pc attributes to be under comp_unit_die so the - debugger can find it. For inlines, that is the concrete instance, - so we can use the old DIE here. For non-inline methods, we want a - specification DIE at toplevel, so we need a new DIE. For local - class methods, this does not apply. */ - if ((DECL_ABSTRACT (decl) || old_die->die_parent == comp_unit_die - || context_die == NULL) - && get_AT_unsigned (old_die, DW_AT_decl_file) == file_index - && (get_AT_unsigned (old_die, DW_AT_decl_line) - == DECL_SOURCE_LINE (decl))) - { - subr_die = old_die; - - /* Clear out the declaration attribute and the parm types. */ - remove_AT (subr_die, DW_AT_declaration); - remove_children (subr_die); - } - else - { - subr_die = new_die (DW_TAG_subprogram, context_die); - add_AT_die_ref (subr_die, DW_AT_specification, old_die); - if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index) - add_AT_unsigned (subr_die, DW_AT_decl_file, file_index); - if (get_AT_unsigned (old_die, DW_AT_decl_line) - != DECL_SOURCE_LINE (decl)) - add_AT_unsigned - (subr_die, DW_AT_decl_line, DECL_SOURCE_LINE (decl)); - } - } - else - { - register dw_die_ref scope_die; - - if (DECL_CONTEXT (decl)) - scope_die = scope_die_for (decl, context_die); - else - /* Don't put block extern declarations under comp_unit_die. */ - scope_die = context_die; - - subr_die = new_die (DW_TAG_subprogram, scope_die); - - if (TREE_PUBLIC (decl)) - add_AT_flag (subr_die, DW_AT_external, 1); - - add_name_and_src_coords_attributes (subr_die, decl); - if (debug_info_level > DINFO_LEVEL_TERSE) - { - register tree type = TREE_TYPE (decl); - - add_prototyped_attribute (subr_die, type); - add_type_attribute (subr_die, TREE_TYPE (type), 0, 0, context_die); - } - - add_pure_or_virtual_attribute (subr_die, decl); - if (DECL_ARTIFICIAL (decl)) - add_AT_flag (subr_die, DW_AT_artificial, 1); - if (TREE_PROTECTED (decl)) - add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_protected); - else if (TREE_PRIVATE (decl)) - add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_private); - } - - if (declaration) - { - add_AT_flag (subr_die, DW_AT_declaration, 1); - - /* The first time we see a member function, it is in the context of - the class to which it belongs. We make sure of this by emitting - the class first. The next time is the definition, which is - handled above. The two may come from the same source text. */ - if (DECL_CONTEXT (decl)) - equate_decl_number_to_die (decl, subr_die); - } - else if (DECL_ABSTRACT (decl)) - { - /* ??? Checking DECL_DEFER_OUTPUT is correct for static inline functions, - but not for extern inline functions. We can't get this completely - correct because information about whether the function was declared - inline is not saved anywhere. */ - if (DECL_DEFER_OUTPUT (decl)) - { - if (DECL_INLINE (decl)) - add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined); - else - add_AT_unsigned (subr_die, DW_AT_inline, - DW_INL_declared_not_inlined); - } - else if (DECL_INLINE (decl)) - add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined); - else - abort (); - - equate_decl_number_to_die (decl, subr_die); - } - else if (!DECL_EXTERNAL (decl)) - { - if (origin == NULL_TREE) - equate_decl_number_to_die (decl, subr_die); - - ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL, - current_funcdef_number); - add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id); - ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, - current_funcdef_number); - add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id); - - add_pubname (decl, subr_die); - add_arange (decl, subr_die); - -#ifdef MIPS_DEBUGGING_INFO - /* Add a reference to the FDE for this routine. */ - add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde); -#endif - - /* Define the "frame base" location for this routine. We use the - frame pointer or stack pointer registers, since the RTL for local - variables is relative to one of them. */ - fp_reg - = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx; - add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg)); - -#if 0 - /* ??? This fails for nested inline functions, because context_display - is not part of the state saved/restored for inline functions. */ - if (current_function_needs_context) - add_AT_location_description (subr_die, DW_AT_static_link, - lookup_static_chain (decl)); -#endif - } - - /* Now output descriptions of the arguments for this function. This gets - (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list - for a FUNCTION_DECL doesn't indicate cases where there was a trailing - `...' at the end of the formal parameter list. In order to find out if - there was a trailing ellipsis or not, we must instead look at the type - associated with the FUNCTION_DECL. This will be a node of type - FUNCTION_TYPE. If the chain of type nodes hanging off of this - FUNCTION_TYPE node ends with a void_type_node then there should *not* be - an ellipsis at the end. */ - push_decl_scope (decl); - - /* In the case where we are describing a mere function declaration, all we - need to do here (and all we *can* do here) is to describe the *types* of - its formal parameters. */ - if (debug_info_level <= DINFO_LEVEL_TERSE) - ; - else if (declaration) - gen_formal_types_die (TREE_TYPE (decl), subr_die); - else - { - /* Generate DIEs to represent all known formal parameters */ - register tree arg_decls = DECL_ARGUMENTS (decl); - register tree parm; - - /* When generating DIEs, generate the unspecified_parameters DIE - instead if we come across the arg "__builtin_va_alist" */ - for (parm = arg_decls; parm; parm = TREE_CHAIN (parm)) - if (TREE_CODE (parm) == PARM_DECL) - { - if (DECL_NAME (parm) - && !strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)), - "__builtin_va_alist")) - gen_unspecified_parameters_die (parm, subr_die); - else - gen_decl_die (parm, subr_die); - } - - /* Decide whether we need a unspecified_parameters DIE at the end. - There are 2 more cases to do this for: 1) the ansi ... declaration - - this is detectable when the end of the arg list is not a - void_type_node 2) an unprototyped function declaration (not a - definition). This just means that we have no info about the - parameters at all. */ - fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); - if (fn_arg_types != NULL) - { - /* this is the prototyped case, check for ... */ - if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node) - gen_unspecified_parameters_die (decl, subr_die); - } - else if (DECL_INITIAL (decl) == NULL_TREE) - gen_unspecified_parameters_die (decl, subr_die); - } - - /* Output Dwarf info for all of the stuff within the body of the function - (if it has one - it may be just a declaration). */ - outer_scope = DECL_INITIAL (decl); - - /* Note that here, `outer_scope' is a pointer to the outermost BLOCK - node created to represent a function. This outermost BLOCK actually - represents the outermost binding contour for the function, i.e. the - contour in which the function's formal parameters and labels get - declared. Curiously, it appears that the front end doesn't actually - put the PARM_DECL nodes for the current function onto the BLOCK_VARS - list for this outer scope. (They are strung off of the DECL_ARGUMENTS - list for the function instead.) The BLOCK_VARS list for the - `outer_scope' does provide us with a list of the LABEL_DECL nodes for - the function however, and we output DWARF info for those in - decls_for_scope. Just within the `outer_scope' there will be a BLOCK - node representing the function's outermost pair of curly braces, and - any blocks used for the base and member initializers of a C++ - constructor function. */ - if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK) - { - current_function_has_inlines = 0; - decls_for_scope (outer_scope, subr_die, 0); - -#if 0 && defined (MIPS_DEBUGGING_INFO) - if (current_function_has_inlines) - { - add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1); - if (! comp_unit_has_inlines) - { - add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1); - comp_unit_has_inlines = 1; - } - } -#endif - } - - pop_decl_scope (); -} - -/* Generate a DIE to represent a declared data object. */ - -static void -gen_variable_die (decl, context_die) - register tree decl; - register dw_die_ref context_die; -{ - register tree origin = decl_ultimate_origin (decl); - register dw_die_ref var_die = new_die (DW_TAG_variable, context_die); - - dw_die_ref old_die = lookup_decl_die (decl); - int declaration - = (DECL_EXTERNAL (decl) - || current_function_decl != decl_function_context (decl) - || context_die->die_tag == DW_TAG_structure_type - || context_die->die_tag == DW_TAG_union_type); - - if (origin != NULL) - add_abstract_origin_attribute (var_die, origin); - /* Loop unrolling can create multiple blocks that refer to the same - static variable, so we must test for the DW_AT_declaration flag. */ - /* ??? Loop unrolling/reorder_blocks should perhaps be rewritten to - copy decls and set the DECL_ABSTRACT flag on them instead of - sharing them. */ - else if (old_die && TREE_STATIC (decl) - && get_AT_flag (old_die, DW_AT_declaration) == 1) - { - /* ??? This is an instantiation of a C++ class level static. */ - add_AT_die_ref (var_die, DW_AT_specification, old_die); - if (DECL_NAME (decl)) - { - register unsigned file_index - = lookup_filename (DECL_SOURCE_FILE (decl)); - - if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index) - add_AT_unsigned (var_die, DW_AT_decl_file, file_index); - - if (get_AT_unsigned (old_die, DW_AT_decl_line) - != DECL_SOURCE_LINE (decl)) - - add_AT_unsigned (var_die, DW_AT_decl_line, - DECL_SOURCE_LINE (decl)); - } - } - else - { - add_name_and_src_coords_attributes (var_die, decl); - add_type_attribute (var_die, TREE_TYPE (decl), - TREE_READONLY (decl), - TREE_THIS_VOLATILE (decl), context_die); - - if (TREE_PUBLIC (decl)) - add_AT_flag (var_die, DW_AT_external, 1); - - if (DECL_ARTIFICIAL (decl)) - add_AT_flag (var_die, DW_AT_artificial, 1); - - if (TREE_PROTECTED (decl)) - add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_protected); - - else if (TREE_PRIVATE (decl)) - add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_private); - } - - if (declaration) - add_AT_flag (var_die, DW_AT_declaration, 1); - - if ((declaration && decl_class_context (decl)) || DECL_ABSTRACT (decl)) - equate_decl_number_to_die (decl, var_die); - - if (! declaration && ! DECL_ABSTRACT (decl)) - { - equate_decl_number_to_die (decl, var_die); - add_location_or_const_value_attribute (var_die, decl); - add_pubname (decl, var_die); - } -} - -/* Generate a DIE to represent a label identifier. */ - -static void -gen_label_die (decl, context_die) - register tree decl; - register dw_die_ref context_die; -{ - register tree origin = decl_ultimate_origin (decl); - register dw_die_ref lbl_die = new_die (DW_TAG_label, context_die); - register rtx insn; - char label[MAX_ARTIFICIAL_LABEL_BYTES]; - char label2[MAX_ARTIFICIAL_LABEL_BYTES]; - - if (origin != NULL) - add_abstract_origin_attribute (lbl_die, origin); - else - add_name_and_src_coords_attributes (lbl_die, decl); - - if (DECL_ABSTRACT (decl)) - equate_decl_number_to_die (decl, lbl_die); - else - { - insn = DECL_RTL (decl); - - /* Deleted labels are programmer specified labels which have been - eliminated because of various optimisations. We still emit them - here so that it is possible to put breakpoints on them. */ - if (GET_CODE (insn) == CODE_LABEL - || ((GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL))) - { - /* When optimization is enabled (via -O) some parts of the compiler - (e.g. jump.c and cse.c) may try to delete CODE_LABEL insns which - represent source-level labels which were explicitly declared by - the user. This really shouldn't be happening though, so catch - it if it ever does happen. */ - if (INSN_DELETED_P (insn)) - abort (); - - sprintf (label2, INSN_LABEL_FMT, current_funcdef_number); - ASM_GENERATE_INTERNAL_LABEL (label, label2, - (unsigned) INSN_UID (insn)); - add_AT_lbl_id (lbl_die, DW_AT_low_pc, label); - } - } -} - -/* Generate a DIE for a lexical block. */ - -static void -gen_lexical_block_die (stmt, context_die, depth) - register tree stmt; - register dw_die_ref context_die; - int depth; -{ - register dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die); - char label[MAX_ARTIFICIAL_LABEL_BYTES]; - - if (! BLOCK_ABSTRACT (stmt)) - { - ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, - next_block_number); - add_AT_lbl_id (stmt_die, DW_AT_low_pc, label); - ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number); - add_AT_lbl_id (stmt_die, DW_AT_high_pc, label); - } - - push_decl_scope (stmt); - decls_for_scope (stmt, stmt_die, depth); - pop_decl_scope (); -} - -/* Generate a DIE for an inlined subprogram. */ - -static void -gen_inlined_subroutine_die (stmt, context_die, depth) - register tree stmt; - register dw_die_ref context_die; - int depth; -{ - if (! BLOCK_ABSTRACT (stmt)) - { - register dw_die_ref subr_die - = new_die (DW_TAG_inlined_subroutine, context_die); - register tree decl = block_ultimate_origin (stmt); - char label[MAX_ARTIFICIAL_LABEL_BYTES]; - - add_abstract_origin_attribute (subr_die, decl); - ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL, - next_block_number); - add_AT_lbl_id (subr_die, DW_AT_low_pc, label); - ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number); - add_AT_lbl_id (subr_die, DW_AT_high_pc, label); - push_decl_scope (decl); - decls_for_scope (stmt, subr_die, depth); - pop_decl_scope (); - current_function_has_inlines = 1; - } -} - -/* Generate a DIE for a field in a record, or structure. */ - -static void -gen_field_die (decl, context_die) - register tree decl; - register dw_die_ref context_die; -{ - register dw_die_ref decl_die = new_die (DW_TAG_member, context_die); - - add_name_and_src_coords_attributes (decl_die, decl); - add_type_attribute (decl_die, member_declared_type (decl), - TREE_READONLY (decl), TREE_THIS_VOLATILE (decl), - context_die); - - /* If this is a bit field... */ - if (DECL_BIT_FIELD_TYPE (decl)) - { - add_byte_size_attribute (decl_die, decl); - add_bit_size_attribute (decl_die, decl); - add_bit_offset_attribute (decl_die, decl); - } - - if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE) - add_data_member_location_attribute (decl_die, decl); - - if (DECL_ARTIFICIAL (decl)) - add_AT_flag (decl_die, DW_AT_artificial, 1); - - if (TREE_PROTECTED (decl)) - add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected); - - else if (TREE_PRIVATE (decl)) - add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private); -} - -#if 0 -/* Don't generate either pointer_type DIEs or reference_type DIEs here. - Use modified_type_die instead. - We keep this code here just in case these types of DIEs may be needed to - represent certain things in other languages (e.g. Pascal) someday. */ -static void -gen_pointer_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref ptr_die - = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die)); - - equate_type_number_to_die (type, ptr_die); - add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die); - add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); -} - -/* Don't generate either pointer_type DIEs or reference_type DIEs here. - Use modified_type_die instead. - We keep this code here just in case these types of DIEs may be needed to - represent certain things in other languages (e.g. Pascal) someday. */ -static void -gen_reference_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref ref_die - = new_die (DW_TAG_reference_type, scope_die_for (type, context_die)); - - equate_type_number_to_die (type, ref_die); - add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die); - add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE); -} -#endif - -/* Generate a DIE for a pointer to a member type. */ -static void -gen_ptr_to_mbr_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref ptr_die - = new_die (DW_TAG_ptr_to_member_type, scope_die_for (type, context_die)); - - equate_type_number_to_die (type, ptr_die); - add_AT_die_ref (ptr_die, DW_AT_containing_type, - lookup_type_die (TYPE_OFFSET_BASETYPE (type))); - add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die); -} - -/* Generate the DIE for the compilation unit. */ - -static void -gen_compile_unit_die (main_input_filename) - register char *main_input_filename; -{ - char producer[250]; - char *wd = getpwd (); - - comp_unit_die = new_die (DW_TAG_compile_unit, NULL); - add_name_attribute (comp_unit_die, main_input_filename); - - if (wd != NULL) - add_AT_string (comp_unit_die, DW_AT_comp_dir, wd); - - sprintf (producer, "%s %s", language_string, version_string); - -#ifdef MIPS_DEBUGGING_INFO - /* The MIPS/SGI compilers place the 'cc' command line options in the producer - string. The SGI debugger looks for -g, -g1, -g2, or -g3; if they do - not appear in the producer string, the debugger reaches the conclusion - that the object file is stripped and has no debugging information. - To get the MIPS/SGI debugger to believe that there is debugging - information in the object file, we add a -g to the producer string. */ - if (debug_info_level > DINFO_LEVEL_TERSE) - strcat (producer, " -g"); -#endif - - add_AT_string (comp_unit_die, DW_AT_producer, producer); - - if (strcmp (language_string, "GNU C++") == 0) - add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C_plus_plus); - - else if (strcmp (language_string, "GNU Ada") == 0) - add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Ada83); - - else if (strcmp (language_string, "GNU F77") == 0) - add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Fortran77); - - else if (strcmp (language_string, "GNU Pascal") == 0) - add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Pascal83); - - else if (flag_traditional) - add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C); - - else - add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C89); - -#if 0 /* unimplemented */ - if (debug_info_level >= DINFO_LEVEL_VERBOSE) - add_AT_unsigned (comp_unit_die, DW_AT_macro_info, 0); -#endif -} - -/* Generate a DIE for a string type. */ - -static void -gen_string_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref type_die - = new_die (DW_TAG_string_type, scope_die_for (type, context_die)); - - equate_type_number_to_die (type, type_die); - - /* Fudge the string length attribute for now. */ - - /* TODO: add string length info. - string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type))); - bound_representation (upper_bound, 0, 'u'); */ -} - -/* Generate the DIE for a base class. */ - -static void -gen_inheritance_die (binfo, context_die) - register tree binfo; - register dw_die_ref context_die; -{ - dw_die_ref die = new_die (DW_TAG_inheritance, context_die); - - add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die); - add_data_member_location_attribute (die, binfo); - - if (TREE_VIA_VIRTUAL (binfo)) - add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual); - if (TREE_VIA_PUBLIC (binfo)) - add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public); - else if (TREE_VIA_PROTECTED (binfo)) - add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected); -} - -/* Generate a DIE for a class member. */ - -static void -gen_member_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register tree member; - - /* If this is not an incomplete type, output descriptions of each of its - members. Note that as we output the DIEs necessary to represent the - members of this record or union type, we will also be trying to output - DIEs to represent the *types* of those members. However the `type' - function (above) will specifically avoid generating type DIEs for member - types *within* the list of member DIEs for this (containing) type execpt - for those types (of members) which are explicitly marked as also being - members of this (containing) type themselves. The g++ front- end can - force any given type to be treated as a member of some other - (containing) type by setting the TYPE_CONTEXT of the given (member) type - to point to the TREE node representing the appropriate (containing) - type. */ - - /* First output info about the base classes. */ - if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type)) - { - register tree bases = TYPE_BINFO_BASETYPES (type); - register int n_bases = TREE_VEC_LENGTH (bases); - register int i; - - for (i = 0; i < n_bases; i++) - gen_inheritance_die (TREE_VEC_ELT (bases, i), context_die); - } - - /* Now output info about the data members and type members. */ - for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member)) - gen_decl_die (member, context_die); - - /* Now output info about the function members (if any). */ - for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member)) - gen_decl_die (member, context_die); -} - -/* Generate a DIE for a structure or union type. */ - -static void -gen_struct_or_union_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register dw_die_ref type_die = lookup_type_die (type); - register dw_die_ref scope_die = 0; - register int nested = 0; - - if (type_die && ! TYPE_SIZE (type)) - return; - - if (TYPE_CONTEXT (type) != NULL_TREE - && AGGREGATE_TYPE_P (TYPE_CONTEXT (type))) - nested = 1; - - scope_die = scope_die_for (type, context_die); - - if (! type_die || (nested && scope_die == comp_unit_die)) - /* First occurrence of type or toplevel definition of nested class. */ - { - register dw_die_ref old_die = type_die; - - type_die = new_die (TREE_CODE (type) == RECORD_TYPE - ? DW_TAG_structure_type : DW_TAG_union_type, - scope_die); - equate_type_number_to_die (type, type_die); - add_name_attribute (type_die, type_tag (type)); - if (old_die) - add_AT_die_ref (type_die, DW_AT_specification, old_die); - } - else - remove_AT (type_die, DW_AT_declaration); - - /* If we're not in the right context to be defining this type, defer to - avoid tricky recursion. */ - if (TYPE_SIZE (type) && decl_scope_depth > 0 && scope_die == comp_unit_die) - { - add_AT_flag (type_die, DW_AT_declaration, 1); - pend_type (type); - } - /* If this type has been completed, then give it a byte_size attribute and - then give a list of members. */ - else if (TYPE_SIZE (type)) - { - /* Prevent infinite recursion in cases where the type of some member of - this type is expressed in terms of this type itself. */ - TREE_ASM_WRITTEN (type) = 1; - add_byte_size_attribute (type_die, type); - if (TYPE_STUB_DECL (type) != NULL_TREE) - add_src_coords_attributes (type_die, TYPE_STUB_DECL (type)); - - /* If the first reference to this type was as the return type of an - inline function, then it may not have a parent. Fix this now. */ - if (type_die->die_parent == NULL) - add_child_die (scope_die, type_die); - - push_decl_scope (type); - gen_member_die (type, type_die); - pop_decl_scope (); - - /* GNU extension: Record what type our vtable lives in. */ - if (TYPE_VFIELD (type)) - { - tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type)); - - gen_type_die (vtype, context_die); - add_AT_die_ref (type_die, DW_AT_containing_type, - lookup_type_die (vtype)); - } - } - else - { - add_AT_flag (type_die, DW_AT_declaration, 1); - - /* We can't do this for function-local types, and we don't need to. */ - if (TREE_PERMANENT (type)) - add_incomplete_type (type); - } -} - -/* Generate a DIE for a subroutine _type_. */ - -static void -gen_subroutine_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - register tree return_type = TREE_TYPE (type); - register dw_die_ref subr_die - = new_die (DW_TAG_subroutine_type, scope_die_for (type, context_die)); - - equate_type_number_to_die (type, subr_die); - add_prototyped_attribute (subr_die, type); - add_type_attribute (subr_die, return_type, 0, 0, context_die); - gen_formal_types_die (type, subr_die); -} - -/* Generate a DIE for a type definition */ - -static void -gen_typedef_die (decl, context_die) - register tree decl; - register dw_die_ref context_die; -{ - register dw_die_ref type_die; - register tree origin; - - if (TREE_ASM_WRITTEN (decl)) - return; - TREE_ASM_WRITTEN (decl) = 1; - - type_die = new_die (DW_TAG_typedef, scope_die_for (decl, context_die)); - origin = decl_ultimate_origin (decl); - if (origin != NULL) - add_abstract_origin_attribute (type_die, origin); - else - { - register tree type; - add_name_and_src_coords_attributes (type_die, decl); - if (DECL_ORIGINAL_TYPE (decl)) - { - type = DECL_ORIGINAL_TYPE (decl); - equate_type_number_to_die (TREE_TYPE (decl), type_die); - } - else - type = TREE_TYPE (decl); - add_type_attribute (type_die, type, TREE_READONLY (decl), - TREE_THIS_VOLATILE (decl), context_die); - } - - if (DECL_ABSTRACT (decl)) - equate_decl_number_to_die (decl, type_die); -} - -/* Generate a type description DIE. */ - -static void -gen_type_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - if (type == NULL_TREE || type == error_mark_node) - return; - - /* We are going to output a DIE to represent the unqualified version of - this type (i.e. without any const or volatile qualifiers) so get the - main variant (i.e. the unqualified version) of this type now. */ - type = type_main_variant (type); - - if (TREE_ASM_WRITTEN (type)) - return; - - if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) - { - TREE_ASM_WRITTEN (type) = 1; - gen_decl_die (TYPE_NAME (type), context_die); - return; - } - - switch (TREE_CODE (type)) - { - case ERROR_MARK: - break; - - case POINTER_TYPE: - case REFERENCE_TYPE: - /* We must set TREE_ASM_WRITTEN in case this is a recursive type. This - ensures that the gen_type_die recursion will terminate even if the - type is recursive. Recursive types are possible in Ada. */ - /* ??? We could perhaps do this for all types before the switch - statement. */ - TREE_ASM_WRITTEN (type) = 1; - - /* For these types, all that is required is that we output a DIE (or a - set of DIEs) to represent the "basis" type. */ - gen_type_die (TREE_TYPE (type), context_die); - break; - - case OFFSET_TYPE: - /* This code is used for C++ pointer-to-data-member types. - Output a description of the relevant class type. */ - gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die); - - /* Output a description of the type of the object pointed to. */ - gen_type_die (TREE_TYPE (type), context_die); - - /* Now output a DIE to represent this pointer-to-data-member type - itself. */ - gen_ptr_to_mbr_type_die (type, context_die); - break; - - case SET_TYPE: - gen_type_die (TYPE_DOMAIN (type), context_die); - gen_set_type_die (type, context_die); - break; - - case FILE_TYPE: - gen_type_die (TREE_TYPE (type), context_die); - abort (); /* No way to represent these in Dwarf yet! */ - break; - - case FUNCTION_TYPE: - /* Force out return type (in case it wasn't forced out already). */ - gen_type_die (TREE_TYPE (type), context_die); - gen_subroutine_type_die (type, context_die); - break; - - case METHOD_TYPE: - /* Force out return type (in case it wasn't forced out already). */ - gen_type_die (TREE_TYPE (type), context_die); - gen_subroutine_type_die (type, context_die); - break; - - case ARRAY_TYPE: - if (TYPE_STRING_FLAG (type) && TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE) - { - gen_type_die (TREE_TYPE (type), context_die); - gen_string_type_die (type, context_die); - } - else - gen_array_type_die (type, context_die); - break; - - case ENUMERAL_TYPE: - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - /* If this is a nested type whose containing class hasn't been - written out yet, writing it out will cover this one, too. */ - if (TYPE_CONTEXT (type) - && AGGREGATE_TYPE_P (TYPE_CONTEXT (type)) - && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) - { - gen_type_die (TYPE_CONTEXT (type), context_die); - - if (TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) - return; - - /* If that failed, attach ourselves to the stub. */ - push_decl_scope (TYPE_CONTEXT (type)); - context_die = lookup_type_die (TYPE_CONTEXT (type)); - } - - if (TREE_CODE (type) == ENUMERAL_TYPE) - gen_enumeration_type_die (type, context_die); - else - gen_struct_or_union_type_die (type, context_die); - - if (TYPE_CONTEXT (type) - && AGGREGATE_TYPE_P (TYPE_CONTEXT (type)) - && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type))) - pop_decl_scope (); - - /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix - it up if it is ever completed. gen_*_type_die will set it for us - when appropriate. */ - return; - - case VOID_TYPE: - case INTEGER_TYPE: - case REAL_TYPE: - case COMPLEX_TYPE: - case BOOLEAN_TYPE: - case CHAR_TYPE: - /* No DIEs needed for fundamental types. */ - break; - - case LANG_TYPE: - /* No Dwarf representation currently defined. */ - break; - - default: - abort (); - } - - TREE_ASM_WRITTEN (type) = 1; -} - -/* Generate a DIE for a tagged type instantiation. */ - -static void -gen_tagged_type_instantiation_die (type, context_die) - register tree type; - register dw_die_ref context_die; -{ - if (type == NULL_TREE || type == error_mark_node) - return; - - /* We are going to output a DIE to represent the unqualified version of - this type (i.e. without any const or volatile qualifiers) so make sure - that we have the main variant (i.e. the unqualified version) of this - type now. */ - if (type != type_main_variant (type) - || !TREE_ASM_WRITTEN (type)) - abort (); - - switch (TREE_CODE (type)) - { - case ERROR_MARK: - break; - - case ENUMERAL_TYPE: - gen_inlined_enumeration_type_die (type, context_die); - break; - - case RECORD_TYPE: - gen_inlined_structure_type_die (type, context_die); - break; - - case UNION_TYPE: - case QUAL_UNION_TYPE: - gen_inlined_union_type_die (type, context_die); - break; - - default: - abort (); - } -} - -/* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the - things which are local to the given block. */ - -static void -gen_block_die (stmt, context_die, depth) - register tree stmt; - register dw_die_ref context_die; - int depth; -{ - register int must_output_die = 0; - register tree origin; - register tree decl; - register enum tree_code origin_code; - - /* Ignore blocks never really used to make RTL. */ - - if (stmt == NULL_TREE || !TREE_USED (stmt)) - return; - - /* Determine the "ultimate origin" of this block. This block may be an - inlined instance of an inlined instance of inline function, so we have - to trace all of the way back through the origin chain to find out what - sort of node actually served as the original seed for the creation of - the current block. */ - origin = block_ultimate_origin (stmt); - origin_code = (origin != NULL) ? TREE_CODE (origin) : ERROR_MARK; - - /* Determine if we need to output any Dwarf DIEs at all to represent this - block. */ - if (origin_code == FUNCTION_DECL) - /* The outer scopes for inlinings *must* always be represented. We - generate DW_TAG_inlined_subroutine DIEs for them. (See below.) */ - must_output_die = 1; - else - { - /* In the case where the current block represents an inlining of the - "body block" of an inline function, we must *NOT* output any DIE for - this block because we have already output a DIE to represent the - whole inlined function scope and the "body block" of any function - doesn't really represent a different scope according to ANSI C - rules. So we check here to make sure that this block does not - represent a "body block inlining" before trying to set the - `must_output_die' flag. */ - if (! is_body_block (origin ? origin : stmt)) - { - /* Determine if this block directly contains any "significant" - local declarations which we will need to output DIEs for. */ - if (debug_info_level > DINFO_LEVEL_TERSE) - /* We are not in terse mode so *any* local declaration counts - as being a "significant" one. */ - must_output_die = (BLOCK_VARS (stmt) != NULL); - else - /* We are in terse mode, so only local (nested) function - definitions count as "significant" local declarations. */ - for (decl = BLOCK_VARS (stmt); - decl != NULL; decl = TREE_CHAIN (decl)) - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_INITIAL (decl)) - { - must_output_die = 1; - break; - } - } - } - - /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block - DIE for any block which contains no significant local declarations at - all. Rather, in such cases we just call `decls_for_scope' so that any - needed Dwarf info for any sub-blocks will get properly generated. Note - that in terse mode, our definition of what constitutes a "significant" - local declaration gets restricted to include only inlined function - instances and local (nested) function definitions. */ - if (must_output_die) - { - if (origin_code == FUNCTION_DECL) - gen_inlined_subroutine_die (stmt, context_die, depth); - else - gen_lexical_block_die (stmt, context_die, depth); - } - else - decls_for_scope (stmt, context_die, depth); -} - -/* Generate all of the decls declared within a given scope and (recursively) - all of its sub-blocks. */ - -static void -decls_for_scope (stmt, context_die, depth) - register tree stmt; - register dw_die_ref context_die; - int depth; -{ - register tree decl; - register tree subblocks; - - /* Ignore blocks never really used to make RTL. */ - if (stmt == NULL_TREE || ! TREE_USED (stmt)) - return; - - if (!BLOCK_ABSTRACT (stmt) && depth > 0) - next_block_number++; - - /* Output the DIEs to represent all of the data objects and typedefs - declared directly within this block but not within any nested - sub-blocks. Also, nested function and tag DIEs have been - generated with a parent of NULL; fix that up now. */ - for (decl = BLOCK_VARS (stmt); - decl != NULL; decl = TREE_CHAIN (decl)) - { - register dw_die_ref die; - - if (TREE_CODE (decl) == FUNCTION_DECL) - die = lookup_decl_die (decl); - else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl)) - die = lookup_type_die (TREE_TYPE (decl)); - else - die = NULL; - - if (die != NULL && die->die_parent == NULL) - add_child_die (context_die, die); - else - gen_decl_die (decl, context_die); - } - - /* Output the DIEs to represent all sub-blocks (and the items declared - therein) of this block. */ - for (subblocks = BLOCK_SUBBLOCKS (stmt); - subblocks != NULL; - subblocks = BLOCK_CHAIN (subblocks)) - gen_block_die (subblocks, context_die, depth + 1); -} - -/* Is this a typedef we can avoid emitting? */ - -static inline int -is_redundant_typedef (decl) - register tree decl; -{ - if (TYPE_DECL_IS_STUB (decl)) - return 1; - - if (DECL_ARTIFICIAL (decl) - && DECL_CONTEXT (decl) - && is_tagged_type (DECL_CONTEXT (decl)) - && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL - && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl)))) - /* Also ignore the artificial member typedef for the class name. */ - return 1; - - return 0; -} - -/* Generate Dwarf debug information for a decl described by DECL. */ - -static void -gen_decl_die (decl, context_die) - register tree decl; - register dw_die_ref context_die; -{ - register tree origin; - - /* Make a note of the decl node we are going to be working on. We may need - to give the user the source coordinates of where it appeared in case we - notice (later on) that something about it looks screwy. */ - dwarf_last_decl = decl; - - if (TREE_CODE (decl) == ERROR_MARK) - return; - - /* If this ..._DECL node is marked to be ignored, then ignore it. But don't - ignore a function definition, since that would screw up our count of - blocks, and that in turn will completely screw up the labels we will - reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for - subsequent blocks). */ - if (DECL_IGNORED_P (decl) && TREE_CODE (decl) != FUNCTION_DECL) - return; - - switch (TREE_CODE (decl)) - { - case CONST_DECL: - /* The individual enumerators of an enum type get output when we output - the Dwarf representation of the relevant enum type itself. */ - break; - - case FUNCTION_DECL: - /* Don't output any DIEs to represent mere function declarations, - unless they are class members or explicit block externs. */ - if (DECL_INITIAL (decl) == NULL_TREE && DECL_CONTEXT (decl) == NULL_TREE - && (current_function_decl == NULL_TREE || ! DECL_ARTIFICIAL (decl))) - break; - - if (debug_info_level > DINFO_LEVEL_TERSE) - { - /* Before we describe the FUNCTION_DECL itself, make sure that we - have described its return type. */ - gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die); - - /* And its containing type. */ - origin = decl_class_context (decl); - if (origin != NULL_TREE) - gen_type_die (origin, context_die); - - /* And its virtual context. */ - if (DECL_VINDEX (decl) != NULL_TREE) - gen_type_die (DECL_CONTEXT (decl), context_die); - } - - /* Now output a DIE to represent the function itself. */ - gen_subprogram_die (decl, context_die); - break; - - case TYPE_DECL: - /* If we are in terse mode, don't generate any DIEs to represent any - actual typedefs. */ - if (debug_info_level <= DINFO_LEVEL_TERSE) - break; - - /* In the special case of a TYPE_DECL node representing the - declaration of some type tag, if the given TYPE_DECL is marked as - having been instantiated from some other (original) TYPE_DECL node - (e.g. one which was generated within the original definition of an - inline function) we have to generate a special (abbreviated) - DW_TAG_structure_type, DW_TAG_union_type, or DW_TAG_enumeration_type - DIE here. */ - if (TYPE_DECL_IS_STUB (decl) && DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE) - { - gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die); - break; - } - - if (is_redundant_typedef (decl)) - gen_type_die (TREE_TYPE (decl), context_die); - else - /* Output a DIE to represent the typedef itself. */ - gen_typedef_die (decl, context_die); - break; - - case LABEL_DECL: - if (debug_info_level >= DINFO_LEVEL_NORMAL) - gen_label_die (decl, context_die); - break; - - case VAR_DECL: - /* If we are in terse mode, don't generate any DIEs to represent any - variable declarations or definitions. */ - if (debug_info_level <= DINFO_LEVEL_TERSE) - break; - - /* Output any DIEs that are needed to specify the type of this data - object. */ - gen_type_die (TREE_TYPE (decl), context_die); - - /* And its containing type. */ - origin = decl_class_context (decl); - if (origin != NULL_TREE) - gen_type_die (origin, context_die); - - /* Now output the DIE to represent the data object itself. This gets - complicated because of the possibility that the VAR_DECL really - represents an inlined instance of a formal parameter for an inline - function. */ - origin = decl_ultimate_origin (decl); - if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL) - gen_formal_parameter_die (decl, context_die); - else - gen_variable_die (decl, context_die); - break; - - case FIELD_DECL: - /* Ignore the nameless fields that are used to skip bits, but - handle C++ anonymous unions. */ - if (DECL_NAME (decl) != NULL_TREE - || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE) - { - gen_type_die (member_declared_type (decl), context_die); - gen_field_die (decl, context_die); - } - break; - - case PARM_DECL: - gen_type_die (TREE_TYPE (decl), context_die); - gen_formal_parameter_die (decl, context_die); - break; - - default: - abort (); - } -} - -/* Write the debugging output for DECL. */ - -void -dwarf2out_decl (decl) - register tree decl; -{ - register dw_die_ref context_die = comp_unit_die; - - if (TREE_CODE (decl) == ERROR_MARK) - return; - - /* If this ..._DECL node is marked to be ignored, then ignore it. We gotta - hope that the node in question doesn't represent a function definition. - If it does, then totally ignoring it is bound to screw up our count of - blocks, and that in turn will completely screw up the labels we will - reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for - subsequent blocks). (It's too bad that BLOCK nodes don't carry their - own sequence numbers with them!) */ - if (DECL_IGNORED_P (decl)) - { - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_INITIAL (decl) != NULL) - abort (); - - return; - } - - switch (TREE_CODE (decl)) - { - case FUNCTION_DECL: - /* Ignore this FUNCTION_DECL if it refers to a builtin declaration of a - builtin function. Explicit programmer-supplied declarations of - these same functions should NOT be ignored however. */ - if (DECL_EXTERNAL (decl) && DECL_FUNCTION_CODE (decl)) - return; - - /* What we would really like to do here is to filter out all mere - file-scope declarations of file-scope functions which are never - referenced later within this translation unit (and keep all of ones - that *are* referenced later on) but we aren't clairvoyant, so we have - no idea which functions will be referenced in the future (i.e. later - on within the current translation unit). So here we just ignore all - file-scope function declarations which are not also definitions. If - and when the debugger needs to know something about these functions, - it wil have to hunt around and find the DWARF information associated - with the definition of the function. Note that we can't just check - `DECL_EXTERNAL' to find out which FUNCTION_DECL nodes represent - definitions and which ones represent mere declarations. We have to - check `DECL_INITIAL' instead. That's because the C front-end - supports some weird semantics for "extern inline" function - definitions. These can get inlined within the current translation - unit (an thus, we need to generate DWARF info for their abstract - instances so that the DWARF info for the concrete inlined instances - can have something to refer to) but the compiler never generates any - out-of-lines instances of such things (despite the fact that they - *are* definitions). The important point is that the C front-end - marks these "extern inline" functions as DECL_EXTERNAL, but we need - to generate DWARF for them anyway. Note that the C++ front-end also - plays some similar games for inline function definitions appearing - within include files which also contain - `#pragma interface' pragmas. */ - if (DECL_INITIAL (decl) == NULL_TREE) - return; - - /* If we're a nested function, initially use a parent of NULL; if we're - a plain function, this will be fixed up in decls_for_scope. If - we're a method, it will be ignored, since we already have a DIE. */ - if (decl_function_context (decl)) - context_die = NULL; - - break; - - case VAR_DECL: - /* Ignore this VAR_DECL if it refers to a file-scope extern data object - declaration and if the declaration was never even referenced from - within this entire compilation unit. We suppress these DIEs in - order to save space in the .debug section (by eliminating entries - which are probably useless). Note that we must not suppress - block-local extern declarations (whether used or not) because that - would screw-up the debugger's name lookup mechanism and cause it to - miss things which really ought to be in scope at a given point. */ - if (DECL_EXTERNAL (decl) && !TREE_USED (decl)) - return; - - /* If we are in terse mode, don't generate any DIEs to represent any - variable declarations or definitions. */ - if (debug_info_level <= DINFO_LEVEL_TERSE) - return; - break; - - case TYPE_DECL: - /* Don't bother trying to generate any DIEs to represent any of the - normal built-in types for the language we are compiling. */ - if (DECL_SOURCE_LINE (decl) == 0) - { - /* OK, we need to generate one for `bool' so GDB knows what type - comparisons have. */ - if ((get_AT_unsigned (comp_unit_die, DW_AT_language) - == DW_LANG_C_plus_plus) - && TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE) - modified_type_die (TREE_TYPE (decl), 0, 0, NULL); - - return; - } - - /* If we are in terse mode, don't generate any DIEs for types. */ - if (debug_info_level <= DINFO_LEVEL_TERSE) - return; - - /* If we're a function-scope tag, initially use a parent of NULL; - this will be fixed up in decls_for_scope. */ - if (decl_function_context (decl)) - context_die = NULL; - - break; - - default: - return; - } - - gen_decl_die (decl, context_die); - output_pending_types_for_scope (comp_unit_die); -} - -/* Output a marker (i.e. a label) for the beginning of the generated code for - a lexical block. */ - -void -dwarf2out_begin_block (blocknum) - register unsigned blocknum; -{ - function_section (current_function_decl); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum); -} - -/* Output a marker (i.e. a label) for the end of the generated code for a - lexical block. */ - -void -dwarf2out_end_block (blocknum) - register unsigned blocknum; -{ - function_section (current_function_decl); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum); -} - -/* Output a marker (i.e. a label) at a point in the assembly code which - corresponds to a given source level label. */ - -void -dwarf2out_label (insn) - register rtx insn; -{ - char label[MAX_ARTIFICIAL_LABEL_BYTES]; - - if (debug_info_level >= DINFO_LEVEL_NORMAL) - { - function_section (current_function_decl); - sprintf (label, INSN_LABEL_FMT, current_funcdef_number); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, label, - (unsigned) INSN_UID (insn)); - } -} - -/* Lookup a filename (in the list of filenames that we know about here in - dwarf2out.c) and return its "index". The index of each (known) filename is - just a unique number which is associated with only that one filename. - We need such numbers for the sake of generating labels - (in the .debug_sfnames section) and references to those - files numbers (in the .debug_srcinfo and.debug_macinfo sections). - If the filename given as an argument is not found in our current list, - add it to the list and assign it the next available unique index number. - In order to speed up searches, we remember the index of the filename - was looked up last. This handles the majority of all searches. */ - -static unsigned -lookup_filename (file_name) - char *file_name; -{ - static unsigned last_file_lookup_index = 0; - register unsigned i; - - /* Check to see if the file name that was searched on the previous call - matches this file name. If so, return the index. */ - if (last_file_lookup_index != 0) - if (strcmp (file_name, file_table[last_file_lookup_index]) == 0) - return last_file_lookup_index; - - /* Didn't match the previous lookup, search the table */ - for (i = 1; i < file_table_in_use; ++i) - if (strcmp (file_name, file_table[i]) == 0) - { - last_file_lookup_index = i; - return i; - } - - /* Prepare to add a new table entry by making sure there is enough space in - the table to do so. If not, expand the current table. */ - if (file_table_in_use == file_table_allocated) - { - file_table_allocated += FILE_TABLE_INCREMENT; - file_table - = (char **) xrealloc (file_table, - file_table_allocated * sizeof (char *)); - } - - /* Add the new entry to the end of the filename table. */ - file_table[file_table_in_use] = xstrdup (file_name); - last_file_lookup_index = file_table_in_use++; - - return last_file_lookup_index; -} - -/* Output a label to mark the beginning of a source code line entry - and record information relating to this source line, in - 'line_info_table' for later output of the .debug_line section. */ - -void -dwarf2out_line (filename, line) - register char *filename; - register unsigned line; -{ - if (debug_info_level >= DINFO_LEVEL_NORMAL) - { - function_section (current_function_decl); - - if (DECL_SECTION_NAME (current_function_decl)) - { - register dw_separate_line_info_ref line_info; - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL, - separate_line_info_table_in_use); - fputc ('\n', asm_out_file); - - /* expand the line info table if necessary */ - if (separate_line_info_table_in_use - == separate_line_info_table_allocated) - { - separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; - separate_line_info_table - = (dw_separate_line_info_ref) - xrealloc (separate_line_info_table, - separate_line_info_table_allocated - * sizeof (dw_separate_line_info_entry)); - } - - /* Add the new entry at the end of the line_info_table. */ - line_info - = &separate_line_info_table[separate_line_info_table_in_use++]; - line_info->dw_file_num = lookup_filename (filename); - line_info->dw_line_num = line; - line_info->function = current_funcdef_number; - } - else - { - register dw_line_info_ref line_info; - - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL, - line_info_table_in_use); - fputc ('\n', asm_out_file); - - /* Expand the line info table if necessary. */ - if (line_info_table_in_use == line_info_table_allocated) - { - line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; - line_info_table - = (dw_line_info_ref) - xrealloc (line_info_table, - (line_info_table_allocated - * sizeof (dw_line_info_entry))); - } - - /* Add the new entry at the end of the line_info_table. */ - line_info = &line_info_table[line_info_table_in_use++]; - line_info->dw_file_num = lookup_filename (filename); - line_info->dw_line_num = line; - } - } -} - -/* Record the beginning of a new source file, for later output - of the .debug_macinfo section. At present, unimplemented. */ - -void -dwarf2out_start_source_file (filename) - register char *filename ATTRIBUTE_UNUSED; -{ -} - -/* Record the end of a source file, for later output - of the .debug_macinfo section. At present, unimplemented. */ - -void -dwarf2out_end_source_file () -{ -} - -/* Called from check_newline in c-parse.y. The `buffer' parameter contains - the tail part of the directive line, i.e. the part which is past the - initial whitespace, #, whitespace, directive-name, whitespace part. */ - -void -dwarf2out_define (lineno, buffer) - register unsigned lineno; - register char *buffer; -{ - static int initialized = 0; - if (!initialized) - { - dwarf2out_start_source_file (primary_filename); - initialized = 1; - } -} - -/* Called from check_newline in c-parse.y. The `buffer' parameter contains - the tail part of the directive line, i.e. the part which is past the - initial whitespace, #, whitespace, directive-name, whitespace part. */ - -void -dwarf2out_undef (lineno, buffer) - register unsigned lineno ATTRIBUTE_UNUSED; - register char *buffer ATTRIBUTE_UNUSED; -{ -} - -/* Set up for Dwarf output at the start of compilation. */ - -void -dwarf2out_init (asm_out_file, main_input_filename) - register FILE *asm_out_file; - register char *main_input_filename; -{ - /* Remember the name of the primary input file. */ - primary_filename = main_input_filename; - - /* Allocate the initial hunk of the file_table. */ - file_table = (char **) xmalloc (FILE_TABLE_INCREMENT * sizeof (char *)); - bzero ((char *) file_table, FILE_TABLE_INCREMENT * sizeof (char *)); - file_table_allocated = FILE_TABLE_INCREMENT; - - /* Skip the first entry - file numbers begin at 1. */ - file_table_in_use = 1; - - /* Allocate the initial hunk of the decl_die_table. */ - decl_die_table - = (dw_die_ref *) xmalloc (DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); - bzero ((char *) decl_die_table, - DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); - decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT; - decl_die_table_in_use = 0; - - /* Allocate the initial hunk of the decl_scope_table. */ - decl_scope_table - = (decl_scope_node *) xmalloc (DECL_SCOPE_TABLE_INCREMENT - * sizeof (decl_scope_node)); - bzero ((char *) decl_scope_table, - DECL_SCOPE_TABLE_INCREMENT * sizeof (decl_scope_node)); - decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT; - decl_scope_depth = 0; - - /* Allocate the initial hunk of the abbrev_die_table. */ - abbrev_die_table - = (dw_die_ref *) xmalloc (ABBREV_DIE_TABLE_INCREMENT - * sizeof (dw_die_ref)); - bzero ((char *) abbrev_die_table, - ABBREV_DIE_TABLE_INCREMENT * sizeof (dw_die_ref)); - abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT; - /* Zero-th entry is allocated, but unused */ - abbrev_die_table_in_use = 1; - - /* Allocate the initial hunk of the line_info_table. */ - line_info_table - = (dw_line_info_ref) xmalloc (LINE_INFO_TABLE_INCREMENT - * sizeof (dw_line_info_entry)); - bzero ((char *) line_info_table, - LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry)); - line_info_table_allocated = LINE_INFO_TABLE_INCREMENT; - /* Zero-th entry is allocated, but unused */ - line_info_table_in_use = 1; - - /* Generate the initial DIE for the .debug section. Note that the (string) - value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE - will (typically) be a relative pathname and that this pathname should be - taken as being relative to the directory from which the compiler was - invoked when the given (base) source file was compiled. */ - gen_compile_unit_die (main_input_filename); - - ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0); - ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label, ABBREV_SECTION_LABEL, 0); - ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0); - ASM_GENERATE_INTERNAL_LABEL (debug_info_section_label, - DEBUG_INFO_SECTION_LABEL, 0); - ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label, - DEBUG_LINE_SECTION_LABEL, 0); - - ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION); - ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label); - ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION); - ASM_OUTPUT_LABEL (asm_out_file, text_section_label); - ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION); - ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label); - ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION); - ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label); -} - -/* Output stuff that dwarf requires at the end of every file, - and generate the DWARF-2 debugging info. */ - -void -dwarf2out_finish () -{ - limbo_die_node *node, *next_node; - dw_die_ref die; - dw_attr_ref a; - - /* Traverse the limbo die list, and add parent/child links. The only - dies without parents that should be here are concrete instances of - inline functions, and the comp_unit_die. We can ignore the comp_unit_die. - For concrete instances, we can get the parent die from the abstract - instance. */ - for (node = limbo_die_list; node; node = next_node) - { - next_node = node->next; - die = node->die; - - if (die->die_parent == NULL) - { - a = get_AT (die, DW_AT_abstract_origin); - if (a) - add_child_die (a->dw_attr_val.v.val_die_ref->die_parent, die); - else if (die == comp_unit_die) - ; - else - abort (); - } - free (node); - } - - /* Walk through the list of incomplete types again, trying once more to - emit full debugging info for them. */ - retry_incomplete_types (); - - /* Traverse the DIE tree and add sibling attributes to those DIE's - that have children. */ - add_sibling_attributes (comp_unit_die); - - /* Output a terminator label for the .text section. */ - fputc ('\n', asm_out_file); - ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0); - -#if 0 - /* Output a terminator label for the .data section. */ - fputc ('\n', asm_out_file); - ASM_OUTPUT_SECTION (asm_out_file, DATA_SECTION); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, DATA_END_LABEL, 0); - - /* Output a terminator label for the .bss section. */ - fputc ('\n', asm_out_file); - ASM_OUTPUT_SECTION (asm_out_file, BSS_SECTION); - ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0); -#endif - - /* Output the source line correspondence table. */ - if (line_info_table_in_use > 1 || separate_line_info_table_in_use) - { - fputc ('\n', asm_out_file); - ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION); - output_line_info (); - - /* We can only use the low/high_pc attributes if all of the code - was in .text. */ - if (separate_line_info_table_in_use == 0) - { - add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label); - add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label); - } - - add_AT_lbl_offset (comp_unit_die, DW_AT_stmt_list, - debug_line_section_label); - } - - /* Output the abbreviation table. */ - fputc ('\n', asm_out_file); - ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION); - build_abbrev_table (comp_unit_die); - output_abbrev_section (); - - /* Initialize the beginning DIE offset - and calculate sizes/offsets. */ - next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE; - calc_die_sizes (comp_unit_die); - - /* Output debugging information. */ - fputc ('\n', asm_out_file); - ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION); - output_compilation_unit_header (); - output_die (comp_unit_die); - - if (pubname_table_in_use) - { - /* Output public names table. */ - fputc ('\n', asm_out_file); - ASM_OUTPUT_SECTION (asm_out_file, PUBNAMES_SECTION); - output_pubnames (); - } - - if (fde_table_in_use) - { - /* Output the address range information. */ - fputc ('\n', asm_out_file); - ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION); - output_aranges (); - } -} -#endif /* DWARF2_DEBUGGING_INFO */ |