/* Output sdb-format symbol table information from GNU compiler.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
This file is part of GCC.
GCC 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
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* mike@tredysvr.Tredydev.Unisys.COM says:
I modified the struct.c example and have a nm of a .o resulting from the
#include "debug.h"
#include "tree.h"
#include "ggc.h"
+#include "varray.h"
static GTY(()) tree anonymous_types;
-/* Counter for sdbout_source_line. */
-
-static GTY(()) int sdbout_source_line_counter;
-
/* Counter to generate unique "names" for nameless struct members. */
static GTY(()) int unnamed_struct_number;
+/* Declarations whose debug info was deferred till end of compilation. */
+
+static GTY(()) varray_type deferred_global_decls;
+
+/* The C front end may call sdbout_symbol before sdbout_init runs.
+ We save all such decls in this list and output them when we get
+ to sdbout_init. */
+
+static GTY(()) tree preinit_symbols;
+static GTY(()) bool sdbout_initialized;
+
#ifdef SDB_DEBUGGING_INFO
#include "rtl.h"
/* 1 if PARM is passed to this function in memory. */
#define PARM_PASSED_IN_MEMORY(PARM) \
- (GET_CODE (DECL_INCOMING_RTL (PARM)) == MEM)
+ (MEM_P (DECL_INCOMING_RTL (PARM)))
/* A C expression for the integer offset value of an automatic variable
(C_AUTO) having address X (an RTX). */
SDB_DELIM, SDB_DELIM, SDB_DELIM, (LINE), SDB_DELIM)
#endif
-#ifndef SDB_GENERATE_FAKE
-#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \
- sprintf ((BUFFER), ".%dfake", (NUMBER));
-#endif
-
/* Return the sdb tag identifier string for TYPE
if TYPE has already been defined; otherwise return a null pointer. */
/* Set the sdb tag identifier string for TYPE to NAME. */
#define SET_KNOWN_TYPE_TAG(TYPE, NAME) \
- TYPE_SYMTAB_POINTER (TYPE) = (char *)(NAME)
+ TYPE_SYMTAB_POINTER (TYPE) = (const char *)(NAME)
/* Return the name (a string) of the struct, union or enum tag
described by the TREE_LIST node LINK. This is 0 for an anonymous one. */
#ifdef MIPS_DEBUGGING_INFO
-#ifndef PUT_SDB_SRC_FILE
-#define PUT_SDB_SRC_FILE(FILENAME) \
-output_file_directive (asm_out_file, (FILENAME))
-#endif
-
/* ECOFF linkers have an optimization that does the same kind of thing as
N_BINCL/E_INCL in stabs: eliminate duplicate debug information in the
executable. To achieve this, GCC must output a .file for each file
sdbout_end_source_file, /* end_source_file */
sdbout_begin_block, /* begin_block */
sdbout_end_block, /* end_block */
- debug_true_tree, /* ignore_block */
+ debug_true_const_tree, /* ignore_block */
sdbout_source_line, /* source_line */
#ifdef MIPS_DEBUGGING_INFO
/* Defer on MIPS systems so that parameter descriptions follow
sdbout_end_function, /* end_function */
debug_nothing_tree, /* function_decl */
sdbout_global_decl, /* global_decl */
+ sdbout_symbol, /* type_decl */
debug_nothing_tree_tree, /* imported_module_or_decl */
debug_nothing_tree, /* deferred_inline_function */
debug_nothing_tree, /* outlining_inline_function */
sdbout_label, /* label */
debug_nothing_int, /* handle_pch */
- debug_nothing_rtx /* var_location */
+ debug_nothing_rtx, /* var_location */
+ debug_nothing_void, /* switch_text_section */
+ 0 /* start_end_main_source_file */
};
/* Return a unique string to name an anonymous type. */
{
char label[10];
char *labelstr;
- SDB_GENERATE_FAKE (label, unnamed_struct_number);
+ sprintf (label, ".%dfake", unnamed_struct_number);
unnamed_struct_number++;
labelstr = xstrdup (label);
return labelstr;
}
if (size == INT_TYPE_SIZE)
- return (TREE_UNSIGNED (type) ? T_UINT : T_INT);
+ return (TYPE_UNSIGNED (type) ? T_UINT : T_INT);
if (size == CHAR_TYPE_SIZE)
- return (TREE_UNSIGNED (type) ? T_UCHAR : T_CHAR);
+ return (TYPE_UNSIGNED (type) ? T_UCHAR : T_CHAR);
if (size == SHORT_TYPE_SIZE)
- return (TREE_UNSIGNED (type) ? T_USHORT : T_SHORT);
+ return (TYPE_UNSIGNED (type) ? T_USHORT : T_SHORT);
if (size == LONG_TYPE_SIZE)
- return (TREE_UNSIGNED (type) ? T_ULONG : T_LONG);
+ return (TYPE_UNSIGNED (type) ? T_ULONG : T_LONG);
if (size == LONG_LONG_TYPE_SIZE) /* better than nothing */
- return (TREE_UNSIGNED (type) ? T_ULONG : T_LONG);
+ return (TYPE_UNSIGNED (type) ? T_ULONG : T_LONG);
return 0;
}
case QUAL_UNION_TYPE:
case ENUMERAL_TYPE:
{
- char *tag;
+ const char *tag;
#ifdef SDB_ALLOW_FORWARD_REFERENCES
sdbout_record_type_name (type);
#endif
int regno = -1;
const char *name;
+ /* If we are called before sdbout_init is run, just save the symbol
+ for later. */
+ if (!sdbout_initialized)
+ {
+ preinit_symbols = tree_cons (0, decl, preinit_symbols);
+ return;
+ }
+
sdbout_one_type (type);
switch (TREE_CODE (decl))
a DECL_INITIAL value of 0. */
if (! DECL_INITIAL (decl))
return;
- if (GET_CODE (DECL_RTL (decl)) != MEM
+ if (!MEM_P (DECL_RTL (decl))
|| GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
return;
PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
return;
if (DECL_IGNORED_P (decl))
return;
+ /* Don't output intrinsic types. GAS chokes on SDB .def
+ statements that contain identifiers with embedded spaces
+ (eg "unsigned long"). */
+ if (DECL_IS_BUILTIN (decl))
+ return;
/* Output typedef name. */
if (template_name_p (DECL_NAME (decl)))
case PARM_DECL:
/* Parm decls go in their own separate chains
and are output by sdbout_reg_parms and sdbout_parms. */
- abort ();
+ gcc_unreachable ();
case VAR_DECL:
/* Don't mention a variable that is external.
If DECL was from an inline function, then its rtl
is not identically the rtl that was used in this
particular compilation. */
- if (GET_CODE (value) == REG)
+ if (REG_P (value))
{
regno = REGNO (value);
if (regno >= FIRST_PSEUDO_REGISTER)
{
while (GET_CODE (value) == SUBREG)
value = SUBREG_REG (value);
- if (GET_CODE (value) == REG)
+ if (REG_P (value))
{
if (REGNO (value) >= FIRST_PSEUDO_REGISTER)
return;
/* Don't output anything if an auto variable
gets RTL that is static.
GAS version 2.2 can't handle such output. */
- else if (GET_CODE (value) == MEM && CONSTANT_P (XEXP (value, 0))
+ else if (MEM_P (value) && CONSTANT_P (XEXP (value, 0))
&& ! TREE_STATIC (decl))
return;
/* Defer SDB information for top-level initialized variables! */
if (! local
- && GET_CODE (value) == MEM
+ && MEM_P (value)
&& DECL_INITIAL (decl))
return;
else
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- if (GET_CODE (value) == MEM
+ if (MEM_P (value)
&& GET_CODE (XEXP (value, 0)) == SYMBOL_REF)
{
PUT_SDB_DEF (name);
PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (regno));
PUT_SDB_SCL (C_REG);
}
- else if (GET_CODE (value) == MEM
- && (GET_CODE (XEXP (value, 0)) == MEM
- || (GET_CODE (XEXP (value, 0)) == REG
+ else if (MEM_P (value)
+ && (MEM_P (XEXP (value, 0))
+ || (REG_P (XEXP (value, 0))
&& REGNO (XEXP (value, 0)) != HARD_FRAME_POINTER_REGNUM
&& REGNO (XEXP (value, 0)) != STACK_POINTER_REGNUM)))
/* If the value is indirect by memory or by a register
so all we can do is output the variable as a pointer. */
{
PUT_SDB_DEF (name);
- if (GET_CODE (XEXP (value, 0)) == REG)
+ if (REG_P (XEXP (value, 0)))
{
PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (XEXP (value, 0))));
PUT_SDB_SCL (C_REG);
type = make_node (POINTER_TYPE);
TREE_TYPE (type) = TREE_TYPE (decl);
}
- else if (GET_CODE (value) == MEM
+ else if (MEM_P (value)
&& ((GET_CODE (XEXP (value, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (value, 0), 0)) == REG
+ && REG_P (XEXP (XEXP (value, 0), 0))
&& GET_CODE (XEXP (XEXP (value, 0), 1)) == CONST_INT)
/* This is for variables which are at offset zero from
the frame pointer. This happens on the Alpha.
Non-frame pointer registers are excluded above. */
- || (GET_CODE (XEXP (value, 0)) == REG)))
+ || (REG_P (XEXP (value, 0)))))
{
/* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...)))
or (MEM (REG...)). We want the value of that CONST_INT
if (DECL_IGNORED_P (decl))
return;
- if (! (TREE_CODE (decl) == VAR_DECL
- && GET_CODE (DECL_RTL (decl)) == MEM
- && DECL_INITIAL (decl)))
- abort ();
+ gcc_assert (TREE_CODE (decl) == VAR_DECL);
+ gcc_assert (MEM_P (DECL_RTL (decl)));
+ gcc_assert (DECL_INITIAL (decl));
PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
PUT_SDB_VAL (XEXP (DECL_RTL (decl), 0));
&& DECL_SECTION_NAME (current_function_decl) != NULL_TREE)
; /* Don't change section amid function. */
else
- text_section ();
+ switch_to_section (text_section);
switch (TREE_CODE (type))
{
int size = int_size_in_bytes (type);
int member_scl = 0;
tree tem;
- int i, n_baseclasses = 0;
/* Record the type tag, but not in its permanent place just yet. */
sdbout_record_type_name (type);
/* This is only relevant to aggregate types. TYPE_BINFO is used
for other purposes in an ENUMERAL_TYPE, so we must exclude that
case. */
- if (TREE_CODE (type) != ENUMERAL_TYPE)
+ if (TREE_CODE (type) != ENUMERAL_TYPE && TYPE_BINFO (type))
{
- if (TYPE_BINFO (type)
- && TYPE_BINFO_BASETYPES (type))
- n_baseclasses = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type));
- for (i = 0; i < n_baseclasses; i++)
+ int i;
+ tree binfo, child;
+
+ for (binfo = TYPE_BINFO (type), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, child); i++)
{
- tree child = TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (type)),
- i);
tree child_type = BINFO_TYPE (child);
tree child_type_name;
+
if (TYPE_NAME (child_type) == 0)
continue;
if (TREE_CODE (TYPE_NAME (child_type)) == IDENTIFIER_NODE)
if (TREE_CODE (type) == ENUMERAL_TYPE)
{
- for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
+ for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem))
if (host_integerp (TREE_VALUE (tem), 0))
{
PUT_SDB_DEF (IDENTIFIER_POINTER (TREE_PURPOSE (tem)));
else
current_sym_value = 0;
- if (GET_CODE (DECL_RTL (parms)) == REG
+ if (REG_P (DECL_RTL (parms))
&& REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER)
type = DECL_ARG_TYPE (parms);
else
(GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms)))
- GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))));
- if (GET_CODE (DECL_RTL (parms)) == MEM
+ if (MEM_P (DECL_RTL (parms))
&& GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS
&& (GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1))
== CONST_INT)
PUT_SDB_TYPE (plain_type (type));
PUT_SDB_ENDEF;
}
- else if (GET_CODE (DECL_RTL (parms)) == REG)
+ else if (REG_P (DECL_RTL (parms)))
{
rtx best_rtl;
/* Parm passed in registers and lives in registers or nowhere. */
PUT_SDB_TYPE (plain_type (TREE_TYPE (parms)));
PUT_SDB_ENDEF;
}
- else if (GET_CODE (DECL_RTL (parms)) == MEM
+ else if (MEM_P (DECL_RTL (parms))
&& XEXP (DECL_RTL (parms), 0) != const0_rtx)
{
/* Parm was passed in registers but lives on the stack. */
in which case we want the value of that CONST_INT,
or (MEM (REG ...)) or (MEM (MEM ...)),
in which case we use a value of zero. */
- if (GET_CODE (XEXP (DECL_RTL (parms), 0)) == REG
- || GET_CODE (XEXP (DECL_RTL (parms), 0)) == MEM)
+ if (REG_P (XEXP (DECL_RTL (parms), 0))
+ || MEM_P (XEXP (DECL_RTL (parms), 0)))
current_sym_value = 0;
else
current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1));
/* Report parms that live in registers during the function
but were passed in memory. */
- if (GET_CODE (DECL_RTL (parms)) == REG
+ if (REG_P (DECL_RTL (parms))
&& REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER
&& PARM_PASSED_IN_MEMORY (parms))
{
PUT_SDB_ENDEF;
}
/* Report parms that live in memory but not where they were passed. */
- else if (GET_CODE (DECL_RTL (parms)) == MEM
+ else if (MEM_P (DECL_RTL (parms))
&& GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS
&& GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT
&& PARM_PASSED_IN_MEMORY (parms)
sdbout_finish (). */
if (!DECL_INITIAL (decl) || !TREE_PUBLIC (decl))
sdbout_symbol (decl, 0);
+ else
+ VARRAY_PUSH_TREE (deferred_global_decls, decl);
/* Output COFF information for non-global file-scope initialized
variables. */
- if (DECL_INITIAL (decl) && GET_CODE (DECL_RTL (decl)) == MEM)
+ if (DECL_INITIAL (decl) && MEM_P (DECL_RTL (decl)))
sdbout_toplevel_data (decl);
}
}
static void
sdbout_finish (const char *main_filename ATTRIBUTE_UNUSED)
{
- tree decl = (*lang_hooks.decls.getdecls) ();
- unsigned int len = list_length (decl);
- tree *vec = xmalloc (sizeof (tree) * len);
- unsigned int i;
-
- /* Process the decls in reverse order--earliest first. Put them
- into VEC from back to front, then take out from front. */
+ size_t i;
- for (i = 0; i < len; i++, decl = TREE_CHAIN (decl))
- vec[len - i - 1] = decl;
-
- for (i = 0; i < len; i++)
- {
- decl = vec[i];
- if (TREE_CODE (decl) == VAR_DECL
- && ! DECL_EXTERNAL (decl)
- && DECL_INITIAL (decl)
- && TREE_PUBLIC (decl)
- && DECL_RTL_SET_P (decl))
- sdbout_symbol (decl, 0);
- }
-
- free (vec);
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_global_decls); i++)
+ sdbout_symbol (VARRAY_TREE (deferred_global_decls, i), 0);
}
/* Describe the beginning of an internal block within a function.
/* COFF relative line numbers must be positive. */
if ((int) line > sdb_begin_function_line)
{
-#ifdef ASM_OUTPUT_SOURCE_LINE
- sdbout_source_line_counter += 1;
- ASM_OUTPUT_SOURCE_LINE (asm_out_file, line, sdbout_source_line_counter);
+#ifdef SDB_OUTPUT_SOURCE_LINE
+ SDB_OUTPUT_SOURCE_LINE (asm_out_file, line);
#else
fprintf (asm_out_file, "\t.ln\t%d\n",
((sdb_begin_function_line > -1)
n->next = current_file;
n->name = filename;
current_file = n;
- PUT_SDB_SRC_FILE (filename);
+ output_file_directive (asm_out_file, filename);
#endif
}
next = current_file->next;
free (current_file);
current_file = next;
- PUT_SDB_SRC_FILE (current_file->name);
+ output_file_directive (asm_out_file, current_file->name);
#endif
}
static void
sdbout_init (const char *input_file_name ATTRIBUTE_UNUSED)
{
+ tree t;
+
#ifdef MIPS_DEBUGGING_INFO
current_file = xmalloc (sizeof *current_file);
current_file->next = NULL;
current_file->name = input_file_name;
#endif
+
+ VARRAY_TREE_INIT (deferred_global_decls, 12, "deferred_global_decls");
+
+ /* Emit debug information which was queued by sdbout_symbol before
+ we got here. */
+ sdbout_initialized = true;
+
+ for (t = nreverse (preinit_symbols); t; t = TREE_CHAIN (t))
+ sdbout_symbol (TREE_VALUE (t), 0);
+ preinit_symbols = 0;
}
#else /* SDB_DEBUGGING_INFO */