/* Output Dwarf2 format symbol table information from the GNU C compiler.
- Copyright (C) 1992, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 95, 96, 97, 1998 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).
information. */
#include "config.h"
+#include "system.h"
#include "defaults.h"
-#include <stdio.h>
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
#include "tree.h"
#include "flags.h"
#include "rtl.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. */
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
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.
#ifndef ASM_OUTPUT_DWARF_DATA1
#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \
- fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, VALUE)
+ fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) (VALUE))
#endif
#ifndef ASM_OUTPUT_DWARF_DELTA1
} 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))
#ifndef ASM_OUTPUT_DWARF_DATA2
#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \
- fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) 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)
+ 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)
+ (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)
+ (unsigned long) (VALUE))
#endif
#ifndef ASM_OUTPUT_DWARF_DATA8
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);\
+ 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); \
+ 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
#endif
/* Return a pointer to a copy of the section string name S with all
- attributes stripped off. */
+ attributes stripped off, and an asterisk prepended (for assemble_name). */
static inline char *
stripattributes (s)
char *s;
{
- char *stripped = xstrdup (s);
+ char *stripped = xmalloc (strlen (s) + 2);
char *p = stripped;
- while (*p && *p != ',')
- p++;
+ *p++ = '*';
+
+ while (*s && *s != ',')
+ *p++ = *s++;
*p = '\0';
return stripped;
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 (mode == CCmode)
+ 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 = GET_MODE_SIZE (reg_raw_mode[i]);
+ ranges[n_ranges].size = last_size = size;
++n_ranges;
if (n_ranges >= 5)
abort ();
}
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);
- size = DWARF_FRAME_REGNUM (ranges[n_ranges].beg);
- for (; n_ranges--; )
+ do
{
- if ((DWARF_FRAME_REGNUM (ranges[n_ranges].end)
- - DWARF_FRAME_REGNUM (ranges[n_ranges].beg))
- != ranges[n_ranges].end - ranges[n_ranges].beg)
+ 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 ();
- if (DWARF_FRAME_REGNUM (ranges[n_ranges].beg) >= size)
+ last_end = end;
+ if (end - beg != ranges[n_ranges].end - ranges[n_ranges].beg)
abort ();
- size = DWARF_FRAME_REGNUM (ranges[n_ranges].beg);
t2 = fold (build (LE_EXPR, integer_type_node, reg_tree,
- build_int_2 (DWARF_FRAME_REGNUM
- (ranges[n_ranges].end), 0)));
+ 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);
}
/* 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. */
cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
- if (sreg == -1)
+ /* 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
char *label;
long size;
{
- register dw_cfi_ref cfi = new_cfi ();
+ 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);
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
label = dwarf2out_cfi_label ();
- insn = PATTERN (insn);
+ src = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
+ if (src)
+ insn = XEXP (src, 0);
+ else
+ insn = PATTERN (insn);
+
/* Assume that in a PARALLEL prologue insn, only the first elt is
significant. Currently this is true. */
if (GET_CODE (insn) == PARALLEL)
{
/* Setting FP from SP. */
case REG:
- if (cfa_reg != REGNO (src))
+ if (cfa_reg != (unsigned) REGNO (src))
abort ();
if (REGNO (dest) != STACK_POINTER_REGNUM
&& !(frame_pointer_needed
offset = INTVAL (XEXP (src, 1));
break;
case REG:
- if (REGNO (XEXP (src, 1)) != cfa_temp_reg)
+ if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp_reg)
abort ();
offset = cfa_temp_value;
break;
if (XEXP (src, 0) == hard_frame_pointer_rtx)
{
/* Restoring SP from FP in the epilogue. */
- if (cfa_reg != HARD_FRAME_POINTER_REGNUM)
+ if (cfa_reg != (unsigned) HARD_FRAME_POINTER_REGNUM)
abort ();
cfa_reg = STACK_POINTER_REGNUM;
}
else if (XEXP (src, 0) == hard_frame_pointer_rtx
&& GET_CODE (XEXP (src, 1)) == CONST_INT)
{
- if (cfa_reg != HARD_FRAME_POINTER_REGNUM)
+ if (cfa_reg != (unsigned) HARD_FRAME_POINTER_REGNUM)
abort ();
offset = INTVAL (XEXP (src, 1));
if (GET_CODE (src) == PLUS)
|| XEXP (src, 1) != stack_pointer_rtx)
abort ();
if (GET_CODE (XEXP (src, 0)) != REG
- || REGNO (XEXP (src, 0)) != cfa_temp_reg)
+ || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg)
abort ();
if (cfa_reg != STACK_POINTER_REGNUM)
abort ();
case IOR:
if (GET_CODE (XEXP (src, 0)) != REG
- || REGNO (XEXP (src, 0)) != cfa_temp_reg
- || REGNO (dest) != cfa_temp_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));
if (GET_CODE (src) == MINUS)
offset = -offset;
- if (cfa_store_reg != REGNO (XEXP (XEXP (dest, 0), 0)))
+ 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 ();
}
#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. */
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_DELTA (asm_out_file, l1, "__FRAME_BEGIN__");
+ 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)
fde->dw_fde_end = NULL;
fde->dw_fde_cfi = NULL;
- args_size = 0;
+ args_size = old_args_size = 0;
}
/* Output a marker (i.e. a label) for the absolute end of the generated code
/* And now, the support for symbolic debugging information. */
#ifdef DWARF2_DEBUGGING_INFO
-extern char *getpwd ();
+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'
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 tree *decl_scope_table;
+static decl_scope_node *decl_scope_table;
/* Number of elements currently allocated for the decl_scope_table. */
-static unsigned decl_scope_table_allocated;
+static int decl_scope_table_allocated;
/* Current level of nesting of declaration scopes. */
-static unsigned decl_scope_depth;
+static int decl_scope_depth;
/* Size (in elements) of increments by which we may expand the
decl_scope_table. */
/* Forward declarations for functions defined in this file. */
-static void addr_const_to_string PROTO((char *, rtx));
+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 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));
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));
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] == '*') \
- strcpy (STR, NAME+1); \
- else \
- strcpy (STR, NAME); \
- } \
+#define ASM_NAME_TO_STRING(STR, NAME) \
+ do { \
+ if ((NAME)[0] == '*') \
+ dyn_string_append (STR, NAME + 1); \
+ else \
+ { \
+ dyn_string_append (STR, user_label_prefix); \
+ dyn_string_append (STR, NAME); \
+ } \
+ } \
while (0)
#endif
\f
static void
addr_const_to_string (str, x)
- char *str;
+ dyn_string_t str;
rtx x;
{
char buf1[256];
- char buf2[256];
restart:
- str[0] = '\0';
switch (GET_CODE (x))
{
case PC:
if (flag_pic)
- strcat (str, ",");
+ dyn_string_append (str, ",");
else
abort ();
break;
case SYMBOL_REF:
- ASM_NAME_TO_STRING (buf1, XSTR (x, 0));
- strcat (str, buf1);
+ 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 (buf2, buf1);
- strcat (str, buf2);
+ ASM_NAME_TO_STRING (str, buf1);
break;
case CODE_LABEL:
ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (x));
- ASM_NAME_TO_STRING (buf2, buf1);
- strcat (str, buf2);
+ ASM_NAME_TO_STRING (str, buf1);
break;
case CONST_INT:
sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
- strcat (str, buf1);
+ 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 (buf1, XEXP (x, 0));
- strcat (str, buf1);
+ addr_const_to_string (str, XEXP (x, 0));
break;
case CONST_DOUBLE:
else
sprintf (buf1, HOST_WIDE_INT_PRINT_DEC,
CONST_DOUBLE_LOW (x));
- strcat (str, buf1);
+ dyn_string_append (str, buf1);
}
else
/* We can't handle floating point constants; PRINT_OPERAND must
/* Some assemblers need integer constants to appear last (eg masm). */
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
{
- addr_const_to_string (buf1, XEXP (x, 1));
- strcat (str, buf1);
+ addr_const_to_string (str, XEXP (x, 1));
if (INTVAL (XEXP (x, 0)) >= 0)
- strcat (str, "+");
+ dyn_string_append (str, "+");
- addr_const_to_string (buf1, XEXP (x, 0));
- strcat (str, buf1);
+ addr_const_to_string (str, XEXP (x, 0));
}
else
{
- addr_const_to_string (buf1, XEXP (x, 0));
- strcat (str, buf1);
+ addr_const_to_string (str, XEXP (x, 0));
if (INTVAL (XEXP (x, 1)) >= 0)
- strcat (str, "+");
+ dyn_string_append (str, "+");
- addr_const_to_string (buf1, XEXP (x, 1));
- strcat (str, buf1);
+ addr_const_to_string (str, XEXP (x, 1));
}
break;
if (GET_CODE (x) != MINUS)
goto restart;
- addr_const_to_string (buf1, XEXP (x, 0));
- strcat (str, buf1);
- strcat (str, "-");
+ 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)
{
- strcat (str, ASM_OPEN_PAREN);
- addr_const_to_string (buf1, XEXP (x, 1));
- strcat (str, buf1);
- strcat (str, ASM_CLOSE_PAREN);
+ 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 (buf1, XEXP (x, 1));
- strcat (str, buf1);
- }
+ addr_const_to_string (str, XEXP (x, 1));
break;
case ZERO_EXTEND:
case SIGN_EXTEND:
- addr_const_to_string (buf1, XEXP (x, 0));
- strcat (str, buf1);
+ addr_const_to_string (str, XEXP (x, 0));
break;
default:
addr_to_string (x)
rtx x;
{
- char buf[1024];
- addr_const_to_string (buf, x);
- return xstrdup (buf);
+ 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. */
/* Convert a DWARF type code into its string name. */
+#if 0
static char *
dwarf_type_encoding_name (enc)
register unsigned enc;
return "DW_ATE_<unknown>";
}
}
+#endif
\f
/* 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
decl_ultimate_origin (decl)
register tree decl;
{
- register tree immediate_origin = DECL_ABSTRACT_ORIGIN (decl);
-
- if (immediate_origin == NULL_TREE)
- return NULL_TREE;
- else
- {
- register tree ret_val;
- register tree lookahead = immediate_origin;
-
- do
- {
- ret_val = lookahead;
- lookahead = DECL_ABSTRACT_ORIGIN (ret_val);
- }
- while (lookahead != NULL && lookahead != ret_val);
+#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 ret_val;
- }
+ return DECL_ABSTRACT_ORIGIN (decl);
}
/* Determine the "ultimate origin" of a block. The block may be an inlined
build_abbrev_table (c);
}
\f
-/* Return the size of a string, including the null byte. */
+/* 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;
{
- register unsigned long size = 0;
- register unsigned long slen = strlen (str);
- register unsigned long i;
- register unsigned c;
-
- for (i = 0; i < slen; ++i)
- {
- c = str[i];
- if (c == '\\')
- ++i;
-
- size += 1;
- }
-
- /* Null terminator. */
- size += 1;
- return size;
+ return strlen (str) + 1;
}
/* Return the size of a location descriptor. */
size += DWARF_LINE_OPCODE_BASE - 1;
/* Include directory table is empty (at present). Count only the
- the null byte used to terminate the table. */
+ null byte used to terminate the table. */
size += 1;
for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
register unsigned long ref_offset;
register unsigned long size;
register dw_loc_descr_ref loc;
- register int i;
output_uleb128 (die->die_abbrev);
if (flag_debug_asm)
break;
case dw_val_class_float:
- 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 %d",
- ASM_COMMENT_START, i);
+ {
+ 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);
- }
+ 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);
else
ASM_OUTPUT_ASCII (asm_out_file,
a->dw_attr_val.v.val_str,
- strlen (a->dw_attr_val.v.val_str) + 1);
+ (int) strlen (a->dw_attr_val.v.val_str) + 1);
break;
default:
}
else
{
- ASM_OUTPUT_ASCII (asm_out_file, pub->name, strlen (pub->name) + 1);
+ ASM_OUTPUT_ASCII (asm_out_file, pub->name,
+ (int) strlen (pub->name) + 1);
}
fputc ('\n', asm_out_file);
ASM_COMMENT_START, 2 * PTR_SIZE);
fputc ('\n', asm_out_file);
- ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_SECTION);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, stripattributes (TEXT_SECTION));
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);
+ ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, text_end_label,
+ stripattributes (TEXT_SECTION));
if (flag_debug_asm)
fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
{
ASM_OUTPUT_ASCII (asm_out_file,
file_table[ft_index],
- strlen (file_table[ft_index]) + 1);
+ (int) strlen (file_table[ft_index]) + 1);
}
fputc ('\n', asm_out_file);
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_SECTION);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, stripattributes (TEXT_SECTION));
fputc ('\n', asm_out_file);
/* 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);
+ strcpy (prev_line_label, stripattributes (TEXT_SECTION));
for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
{
register dw_line_info_ref line_info;
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,
- TYPE_PRECISION (type) / BITS_PER_UNIT);
+ int_size_in_bytes (type));
add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
return base_type_result;
register dw_loc_descr_ref loc_result = NULL;
register unsigned reg = reg_number (rtl);
- if (reg >= 0 && reg <= 31)
+ 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);
if (reg == fp_reg)
loc_result = new_loc_descr (DW_OP_fbreg, offset, 0);
- else if (reg >= 0 && reg <= 31)
+ 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);
{
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,
- SAVE_EXPR_RTL (bound));
+ add_AT_location_description (decl_die, DW_AT_location, loc);
add_AT_die_ref (subrange_die, bound_attr, decl_die);
}
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;
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
- = (tree *) xrealloc (decl_scope_table,
- decl_scope_table_allocated * sizeof (tree));
+ = (decl_scope_node *) xrealloc (decl_scope_table,
+ (decl_scope_table_allocated
+ * sizeof (decl_scope_node)));
}
- decl_scope_table[decl_scope_depth++] = scope;
+ 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 (TREE_CODE_CLASS (TREE_CODE (scope)) == 't')
+ 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 the immediately contains this declaration. */
+/* Return the DIE for the scope that immediately contains this declaration. */
static dw_die_ref
scope_die_for (t, context_die)
{
register dw_die_ref scope_die = NULL;
register tree containing_scope;
- register unsigned long i;
+ register int i;
/* Walk back up the declaration tree looking for a place to define
this type. */
else
containing_scope = DECL_CONTEXT (t);
+ /* Ignore namespaces for the moment. */
+ if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL)
+ 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
scope_die = comp_unit_die;
else
{
- for (i = decl_scope_depth, scope_die = context_die;
- i > 0 && decl_scope_table[i - 1] != containing_scope;
- scope_die = scope_die->die_parent, --i)
+ 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))
;
- if (i == 0)
+ /* ??? 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 (scope_die != comp_unit_die
|| TREE_CODE_CLASS (TREE_CODE (containing_scope)) != 't')
/* 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;
fnname = XSTR (x, 0);
return fnname;
}
+#endif
\f
/* These routines generate the internal representation of the DIE's for
the compilation unit. Debugging information is collected by walking
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;
else
add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
}
+#endif
/* Remember a type in the pending_types_list. */
register tree decl_or_type;
register dw_die_ref context_die;
{
- register dw_die_ref parm_die = new_die (DW_TAG_unspecified_parameters,
- context_die);
+ new_die (DW_TAG_unspecified_parameters, context_die);
}
/* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a
= lookup_filename (DECL_SOURCE_FILE (decl));
if (get_AT_flag (old_die, DW_AT_declaration) != 1)
- abort ();
+ {
+ /* ??? 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
if (type == NULL_TREE || type == error_mark_node)
return;
- /* We are going to output a DIE to represent the unqualified version of of
+ /* 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 (type == NULL_TREE || type == error_mark_node)
return;
- /* We are going to output a DIE to represent the unqualified version of of
+ /* 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. */
}
/* Generate all of the decls declared within a given scope and (recursively)
- all of it's sub-blocks. */
+ all of its sub-blocks. */
static void
decls_for_scope (stmt, context_die, depth)
/* 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 it turn will completely screw up the the labels we will
+ 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)
/* 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 it turn will completely screw up the the labels we will
+ 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)
+ && DECL_INITIAL (decl) != NULL)
abort ();
return;
void
dwarf2out_start_source_file (filename)
- register char *filename;
+ register char *filename ATTRIBUTE_UNUSED;
{
}
void
dwarf2out_undef (lineno, buffer)
- register unsigned lineno;
- register char *buffer;
+ register unsigned lineno ATTRIBUTE_UNUSED;
+ register char *buffer ATTRIBUTE_UNUSED;
{
}
/* Allocate the initial hunk of the decl_scope_table. */
decl_scope_table
- = (tree *) xmalloc (DECL_SCOPE_TABLE_INCREMENT * sizeof (tree));
+ = (decl_scope_node *) xmalloc (DECL_SCOPE_TABLE_INCREMENT
+ * sizeof (decl_scope_node));
bzero ((char *) decl_scope_table,
- DECL_SCOPE_TABLE_INCREMENT * sizeof (tree));
+ DECL_SCOPE_TABLE_INCREMENT * sizeof (decl_scope_node));
decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT;
decl_scope_depth = 0;
was in .text. */
if (separate_line_info_table_in_use == 0)
{
- add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, TEXT_SECTION);
+ add_AT_lbl_id (comp_unit_die, DW_AT_low_pc,
+ stripattributes (TEXT_SECTION));
add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
}