X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fdbxout.c;h=80d2f83849f921455cb515576491e63acb72643a;hb=82280733cf15fa787aa6b87aff533fbdc19fa40a;hp=a39f6515fdb4f56d3540c835903e8a89327ee08e;hpb=aa6d9ad61d83eec48e805f8df7ba7a506c0e39ae;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/dbxout.c b/gcc/dbxout.c index a39f6515fdb..80d2f83849f 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -1,5 +1,5 @@ /* Output dbx-format symbol table information from GNU compiler. - Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc. + Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc. This file is part of GNU CC. @@ -15,7 +15,8 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* Output dbx-format symbol table data. @@ -78,6 +79,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "insn-config.h" #include "reload.h" #include "defaults.h" +#include "output.h" /* ASM_OUTPUT_SOURCE_LINE may refer to sdb functions. */ #ifndef errno extern int errno; @@ -111,14 +113,34 @@ extern int errno; #define DBX_REGPARM_STABS_LETTER 'P' #endif +/* This is used for parameters passed by invisible reference in a register. */ +#ifndef GDB_INV_REF_REGPARM_STABS_LETTER +#define GDB_INV_REF_REGPARM_STABS_LETTER 'a' +#endif + #ifndef DBX_MEMPARM_STABS_LETTER #define DBX_MEMPARM_STABS_LETTER 'p' #endif +#ifndef FILE_NAME_JOINER +#define FILE_NAME_JOINER "/" +#endif + /* Nonzero means if the type has methods, only output debugging - information if methods are actually written to the asm file. */ + information if methods are actually written to the asm file. This + optimization only works if the debugger can detect the special C++ + marker. */ + +#define MINIMAL_DEBUG 1 -static int flag_minimal_debug = 1; +#ifdef NO_DOLLAR_IN_LABEL +#ifdef NO_DOT_IN_LABEL +#undef MINIMAL_DEBUG +#define MINIMAL_DEBUG 0 +#endif +#endif + +static int flag_minimal_debug = MINIMAL_DEBUG; /* Nonzero if we have actually used any of the GDB extensions to the debugging format. The idea is that we use them for the @@ -127,6 +149,13 @@ static int flag_minimal_debug = 1; static int have_used_extensions = 0; +/* Number for the next N_SOL filename stabs label. The number 0 is reserved + for the N_SO filename stabs label. */ + +static int source_label_number = 1; + +static int scope_labelno = 0; + char *getpwd (); /* Typical USG systems don't have stab.h, and they also have @@ -140,7 +169,7 @@ char *getpwd (); #define FORCE_TEXT #endif -#if defined (USG) || defined (NO_STAB_H) +#if defined (USG) || defined (NO_STAB_H) || defined (CROSS_COMPILE) #include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */ #else #include /* On BSD, use the system's stab.h. */ @@ -189,15 +218,28 @@ static char *cwd; enum typestatus {TYPE_UNSEEN, TYPE_XREF, TYPE_DEFINED}; -/* Vector recording the status of describing C data types. +/* Structure recording information about a C data type. + The status element says whether we have yet output + the definition of the type. TYPE_XREF says we have + output it as a cross-reference only. + The file_number and type_number elements are used if DBX_USE_BINCL + is defined. */ + +struct typeinfo +{ + enum typestatus status; +#ifdef DBX_USE_BINCL + int file_number; + int type_number; +#endif +}; + +/* Vector recording information about C data types. When we first notice a data type (a tree node), we assign it a number using next_type_number. - That is its index in this vector. - The vector element says whether we have yet output - the definition of the type. TYPE_XREF says we have - output it as a cross-reference only. */ + That is its index in this vector. */ -enum typestatus *typevec; +struct typeinfo *typevec; /* Number of elements of space allocated in `typevec'. */ @@ -209,6 +251,29 @@ static int typevec_len; static int next_type_number; +#ifdef DBX_USE_BINCL + +/* When using N_BINCL in dbx output, each type number is actually a + pair of the file number and the type number within the file. + This is a stack of input files. */ + +struct dbx_file +{ + struct dbx_file *next; + int file_number; + int next_type_number; +}; + +/* This is the top of the stack. */ + +static struct dbx_file *current_file; + +/* This is the next file number to use. */ + +static int next_file_number; + +#endif /* DBX_USE_BINCL */ + /* In dbx output, we must assign symbol-blocks id numbers in the order in which their beginnings are encountered. We output debugging info that refers to the beginning and @@ -259,119 +324,46 @@ static int current_sym_nchars; void dbxout_types (); void dbxout_args (); void dbxout_symbol (); -static void dbxout_type_name (); -static void dbxout_type (); -static void dbxout_typedefs (); -static void dbxout_prepare_symbol (); -static void dbxout_finish_symbol (); -static void dbxout_continue (); -static void print_int_cst_octal (); -static void print_octal (); + +static void dbxout_function_end PROTO((void)); +static void dbxout_typedefs PROTO((tree)); +static void dbxout_type_index PROTO((tree)); +static void dbxout_continue PROTO((void)); +static void dbxout_type_fields PROTO((tree)); +static void dbxout_type_method_1 PROTO((tree, char *)); +static void dbxout_type_methods PROTO((tree)); +static void dbxout_range_type PROTO((tree)); +static void dbxout_type PROTO((tree, int, int)); +static void print_int_cst_octal PROTO((tree)); +static void print_octal PROTO((unsigned HOST_WIDE_INT, int)); +static void dbxout_type_name PROTO((tree)); +static void dbxout_symbol_location PROTO((tree, tree, char *, rtx)); +static void dbxout_symbol_name PROTO((tree, char *, int)); +static void dbxout_prepare_symbol PROTO((tree)); +static void dbxout_finish_symbol PROTO((tree)); +static void dbxout_block PROTO((tree, int, tree)); +static void dbxout_really_begin_function PROTO((tree)); -#if 0 /* Not clear we will actually need this. */ - -/* Return the absolutized filename for the given relative - filename. Note that if that filename is already absolute, it may - still be returned in a modified form because this routine also - eliminates redundant slashes and single dots and eliminates double - dots to get a shortest possible filename from the given input - filename. The absolutization of relative filenames is made by - assuming that the given filename is to be taken as relative to - the first argument (cwd) or to the current directory if cwd is - NULL. */ - -static char * -abspath (rel_filename) - char *rel_filename; +static void +dbxout_function_end () { - /* Setup the current working directory as needed. */ - char *abs_buffer - = (char *) alloca (strlen (cwd) + strlen (rel_filename) + 1); - char *endp = abs_buffer; - char *outp, *inp; - char *value; - - /* Copy the filename (possibly preceded by the current working - directory name) into the absolutization buffer. */ - - { - char *src_p; - - if (rel_filename[0] != '/') - { - src_p = cwd; - while (*endp++ = *src_p++) - continue; - *(endp-1) = '/'; /* overwrite null */ - } - src_p = rel_filename; - while (*endp++ = *src_p++) - continue; - if (endp[-1] == '/') - *endp = '\0'; - - /* Now make a copy of abs_buffer into abs_buffer, shortening the - filename (by taking out slashes and dots) as we go. */ - - outp = inp = abs_buffer; - *outp++ = *inp++; /* copy first slash */ - for (;;) - { - if (!inp[0]) - break; - else if (inp[0] == '/' && outp[-1] == '/') - { - inp++; - continue; - } - else if (inp[0] == '.' && outp[-1] == '/') - { - if (!inp[1]) - break; - else if (inp[1] == '/') - { - inp += 2; - continue; - } - else if ((inp[1] == '.') && (inp[2] == 0 || inp[2] == '/')) - { - inp += (inp[2] == '/') ? 3 : 2; - outp -= 2; - while (outp >= abs_buffer && *outp != '/') - outp--; - if (outp < abs_buffer) - { - /* Catch cases like /.. where we try to backup to a - point above the absolute root of the logical file - system. */ - - fprintf (stderr, "%s: invalid file name: %s\n", - pname, rel_filename); - exit (1); - } - *++outp = '\0'; - continue; - } - } - *outp++ = *inp++; - } - - /* On exit, make sure that there is a trailing null, and make sure that - the last character of the returned string is *not* a slash. */ - - *outp = '\0'; - if (outp[-1] == '/') - *--outp = '\0'; - - /* Make a copy (in the heap) of the stuff left in the absolutization - buffer and return a pointer to the copy. */ - - value = (char *) oballoc (strlen (abs_buffer) + 1); - strcpy (value, abs_buffer); - return value; + char lscope_label_name[100]; + /* Convert Ltext into the appropriate format for local labels in case + the system doesn't insert underscores in front of user generated + labels. */ + ASM_GENERATE_INTERNAL_LABEL (lscope_label_name, "Lscope", scope_labelno); + ASM_OUTPUT_INTERNAL_LABEL (asmfile, "Lscope", scope_labelno); + scope_labelno++; + + /* By convention, GCC will mark the end of a function with an N_FUN + symbol and an empty string. */ + fprintf (asmfile, "%s \"\",%d,0,0,", ASM_STABS_OP, N_FUN); + assemble_name (asmfile, lscope_label_name); + fputc ('-', asmfile); + assemble_name (asmfile, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); + fprintf (asmfile, "\n"); } -#endif /* 0 */ - + /* At the beginning of compilation, start writing the symbol table. Initialize `typevec' and output the standard data types of C. */ @@ -386,8 +378,8 @@ dbxout_init (asm_file, input_file_name, syms) asmfile = asm_file; typevec_len = 100; - typevec = (enum typestatus *) xmalloc (typevec_len * sizeof typevec[0]); - bzero (typevec, typevec_len * sizeof typevec[0]); + typevec = (struct typeinfo *) xmalloc (typevec_len * sizeof typevec[0]); + bzero ((char *) typevec, typevec_len * sizeof typevec[0]); /* Convert Ltext into the appropriate format for local labels in case the system doesn't insert underscores in front of user generated @@ -400,13 +392,20 @@ dbxout_init (asm_file, input_file_name, syms) if (use_gnu_debug_info_extensions) #endif { - if (cwd || (cwd = getpwd ())) + if (!cwd && (cwd = getpwd ()) && (!*cwd || cwd[strlen (cwd) - 1] != '/')) + { + char *wdslash = xmalloc (strlen (cwd) + sizeof (FILE_NAME_JOINER)); + sprintf (wdslash, "%s%s", cwd, FILE_NAME_JOINER); + cwd = wdslash; + } + if (cwd) { #ifdef DBX_OUTPUT_MAIN_SOURCE_DIRECTORY DBX_OUTPUT_MAIN_SOURCE_DIRECTORY (asmfile, cwd); #else /* no DBX_OUTPUT_MAIN_SOURCE_DIRECTORY */ - fprintf (asmfile, "%s \"%s/\",%d,0,0,%s\n", ASM_STABS_OP, - cwd, N_SO, <ext_label_name[1]); + fprintf (asmfile, "%s ", ASM_STABS_OP); + output_quoted_string (asmfile, cwd); + fprintf (asmfile, ",%d,0,0,%s\n", N_SO, <ext_label_name[1]); #endif /* no DBX_OUTPUT_MAIN_SOURCE_DIRECTORY */ } } @@ -419,7 +418,9 @@ dbxout_init (asm_file, input_file_name, syms) /* We include outputting `Ltext:' here, because that gives you a way to override it. */ /* Used to put `Ltext:' before the reference, but that loses on sun 4. */ - fprintf (asmfile, "%s \"%s\",%d,0,0,%s\n", ASM_STABS_OP, input_file_name, + fprintf (asmfile, "%s ", ASM_STABS_OP); + output_quoted_string (asmfile, input_file_name); + fprintf (asmfile, ",%d,0,0,%s\n", N_SO, <ext_label_name[1]); text_section (); ASM_OUTPUT_INTERNAL_LABEL (asmfile, "Ltext", 0); @@ -437,6 +438,14 @@ dbxout_init (asm_file, input_file_name, syms) next_type_number = 1; next_block_number = 2; +#ifdef DBX_USE_BINCL + current_file = (struct dbx_file *) xmalloc (sizeof *current_file); + current_file->next = NULL; + current_file->file_number = 0; + current_file->next_type_number = 1; + next_file_number = 1; +#endif + /* Make sure that types `int' and `char' have numbers 1 and 2. Definitions of other integer types will refer to those numbers. (Actually it should no longer matter what their numbers are. @@ -472,12 +481,45 @@ dbxout_typedefs (syms) tree type = TREE_TYPE (syms); if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && TYPE_SIZE (type) != NULL_TREE && ! TREE_ASM_WRITTEN (TYPE_NAME (type))) dbxout_symbol (TYPE_NAME (type), 0); } } } +/* Change to reading from a new source file. Generate a N_BINCL stab. */ + +void +dbxout_start_new_source_file (filename) + char *filename; +{ +#ifdef DBX_USE_BINCL + struct dbx_file *n = (struct dbx_file *) xmalloc (sizeof *n); + + n->next = current_file; + n->file_number = next_file_number++; + n->next_type_number = 1; + current_file = n; + fprintf (asmfile, "%s \"%s\",%d,0,0,0\n", ASM_STABS_OP, filename, N_BINCL); +#endif +} + +/* Revert to reading a previous source file. Generate a N_EINCL stab. */ + +void +dbxout_resume_previous_source_file () +{ +#ifdef DBX_USE_BINCL + struct dbx_file *next; + + fprintf (asmfile, "%s %d,0,0,0\n", ASM_STABN_OP, N_EINCL); + next = current_file->next; + free (current_file); + current_file = next; +#endif +} + /* Output debugging info to FILE to switch to sourcefile FILENAME. */ void @@ -492,9 +534,18 @@ dbxout_source_file (file, filename) #ifdef DBX_OUTPUT_SOURCE_FILENAME DBX_OUTPUT_SOURCE_FILENAME (file, filename); #else - ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0); - fprintf (file, "%s \"%s\",%d,0,0,%s\n", ASM_STABS_OP, - filename, N_SOL, <ext_label_name[1]); + ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", + source_label_number); + fprintf (file, "%s ", ASM_STABS_OP); + output_quoted_string (file, filename); + fprintf (file, ",%d,0,0,%s\n", N_SOL, <ext_label_name[1]); + if (current_function_decl != NULL_TREE + && DECL_SECTION_NAME (current_function_decl) != NULL_TREE) + ; /* Don't change section amid function. */ + else + text_section (); + ASM_OUTPUT_INTERNAL_LABEL (file, "Ltext", source_label_number); + source_label_number++; #endif lastfile = filename; } @@ -520,7 +571,7 @@ dbxout_source_line (file, filename, lineno) /* At the end of compilation, finish writing the symbol table. Unless you define DBX_OUTPUT_MAIN_SOURCE_FILE_END, the default is - to do nothing. */ + to do nothing. */ void dbxout_finish (file, filename) @@ -532,6 +583,22 @@ dbxout_finish (file, filename) #endif /* DBX_OUTPUT_MAIN_SOURCE_FILE_END */ } +/* Output the index of a type. */ + +static void +dbxout_type_index (type) + tree type; +{ +#ifndef DBX_USE_BINCL + fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type)); + CHARS (3); +#else + struct typeinfo *t = &typevec[TYPE_SYMTAB_ADDRESS (type)]; + fprintf (asmfile, "(%d,%d)", t->file_number, t->type_number); + CHARS (7); +#endif +} + /* Continue a symbol-description that gets too big. End one symbol table entry with a double-backslash and start a new one, eventually producing something like @@ -560,18 +627,20 @@ dbxout_type_fields (type) tree type; { tree tem; + /* Output the name, type, position (in bits), size (in bits) of each + field. */ for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) { - /* Output the name, type, position (in bits), size (in bits) - of each field. */ - if (DECL_NAME (tem) == NULL_TREE - && TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE) - dbxout_type_fields (TREE_TYPE (tem)); /* Omit here local type decls until we know how to support them. */ - else if (TREE_CODE (tem) == TYPE_DECL) + if (TREE_CODE (tem) == TYPE_DECL) + continue; + /* Omit fields whose position or size are variable. */ + else if (TREE_CODE (tem) == FIELD_DECL + && (TREE_CODE (DECL_FIELD_BITPOS (tem)) != INTEGER_CST + || TREE_CODE (DECL_SIZE (tem)) != INTEGER_CST)) continue; /* Omit here the nameless fields that are used to skip bits. */ - else if (DECL_NAME (tem) != 0 && TREE_CODE (tem) != CONST_DECL) + else if (TREE_CODE (tem) != CONST_DECL) { /* Continue the line if necessary, but not before the first field. */ @@ -585,7 +654,7 @@ dbxout_type_fields (type) && DECL_ASSEMBLER_NAME (tem)) { have_used_extensions = 1; - CHARS (3 + IDENTIFIER_LENGTH (DECL_NAME (TYPE_NAME (DECL_FCONTEXT (tem))))); + CHARS (3 + IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (tem))); fputs (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (tem)), asmfile); dbxout_type (DECL_FCONTEXT (tem), 0, 0); fprintf (asmfile, ":"); @@ -595,8 +664,16 @@ dbxout_type_fields (type) continue; } - fprintf (asmfile, "%s:", IDENTIFIER_POINTER (DECL_NAME (tem))); - CHARS (2 + IDENTIFIER_LENGTH (DECL_NAME (tem))); + if (DECL_NAME (tem)) + { + fprintf (asmfile, "%s:", IDENTIFIER_POINTER (DECL_NAME (tem))); + CHARS (2 + IDENTIFIER_LENGTH (DECL_NAME (tem))); + } + else + { + fprintf (asmfile, ":"); + CHARS (2); + } if (use_gnu_debug_info_extensions && (TREE_PRIVATE (tem) || TREE_PROTECTED (tem) @@ -636,9 +713,6 @@ dbxout_type_fields (type) TREE_INT_CST_LOW (DECL_FIELD_BITPOS (tem)), TREE_INT_CST_LOW (DECL_SIZE (tem))); } - else - /* This has yet to be implemented. */ - abort (); CHARS (23); } } @@ -654,13 +728,13 @@ dbxout_type_method_1 (decl, debug_name) tree decl; char *debug_name; { - tree firstarg = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))); char c1 = 'A', c2; if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE) c2 = '?'; else /* it's a METHOD_TYPE. */ { + tree firstarg = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))); /* A for normal functions. B for `const' member functions. C for `volatile' member functions. @@ -710,6 +784,7 @@ dbxout_type_methods (type) type_encoding = DECL_NAME (TYPE_NAME (type)); +#if 0 /* C++: Template classes break some assumptions made by this code about the class names, constructor names, and encodings for assembler label names. For now, disable output of dbx info for them. */ @@ -723,11 +798,15 @@ dbxout_type_methods (type) if (!warned) { warned = 1; - warning ("dbx info for template class methods not yet supported"); +#ifdef HAVE_TEMPLATES + if (warn_template_debugging) + warning ("dbx info for template class methods not yet supported"); +#endif } return; } } +#endif type_identifier_length = IDENTIFIER_LENGTH (type_encoding); @@ -757,7 +836,7 @@ dbxout_type_methods (type) /* This is the "mangled" name of the method. It encodes the argument types. */ char *debug_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)); - int destructor = 0; + int show_arg_types = 0; CONTIN; @@ -768,10 +847,23 @@ dbxout_type_methods (type) if (flag_minimal_debug) { + char marker; + + /* We can't optimize a method which uses an anonymous + class, because the debugger will not be able to + associate the arbitrary class name with the actual + class. */ +#ifndef NO_DOLLAR_IN_LABEL + marker = '$'; +#else + marker = '.'; +#endif + if (strchr (debug_name, marker)) + show_arg_types = 1; /* Detect ordinary methods because their mangled names start with the operation name. */ - if (!strncmp (IDENTIFIER_POINTER (name), debug_name, - IDENTIFIER_LENGTH (name))) + else if (!strncmp (IDENTIFIER_POINTER (name), debug_name, + IDENTIFIER_LENGTH (name))) { debug_name += IDENTIFIER_LENGTH (name); if (debug_name[0] == '_' && debug_name[1] == '_') @@ -781,7 +873,7 @@ dbxout_type_methods (type) /* Get past const and volatile qualifiers. */ while (*method_name == 'C' || *method_name == 'V') method_name++; - /* Skip digits for length of type_encoding. */ + /* Skip digits for length of type_encoding. */ while (*method_name == *length_ptr && *length_ptr) length_ptr++, method_name++; if (! strncmp (method_name, @@ -798,7 +890,7 @@ dbxout_type_methods (type) char *length_ptr = formatted_type_identifier_length; while (*ctor_name == 'C' || *ctor_name == 'V') ctor_name++; - /* Skip digits for length of type_encoding. */ + /* Skip digits for length of type_encoding. */ while (*ctor_name == *length_ptr && *length_ptr) length_ptr++, ctor_name++; if (!strncmp (IDENTIFIER_POINTER (type_encoding), ctor_name, @@ -807,7 +899,7 @@ dbxout_type_methods (type) } /* The other alternative is a destructor. */ else - destructor = 1; + show_arg_types = 1; /* Output the operation name just once, for the first method that we output. */ @@ -819,7 +911,7 @@ dbxout_type_methods (type) } } - dbxout_type (TREE_TYPE (fndecl), 0, destructor); + dbxout_type (TREE_TYPE (fndecl), 0, show_arg_types); dbxout_type_method_1 (fndecl, debug_name); } @@ -830,6 +922,40 @@ dbxout_type_methods (type) } } } + +/* Emit a "range" type specification, which has the form: + "r;;;". + TYPE is an INTEGER_TYPE. */ + +static void +dbxout_range_type (type) + tree type; +{ + fprintf (asmfile, "r"); + if (TREE_TYPE (type)) + dbxout_type (TREE_TYPE (type), 0, 0); + else if (TREE_CODE (type) != INTEGER_TYPE) + dbxout_type (type, 0, 0); /* E.g. Pascal's ARRAY [BOOLEAN] of INTEGER */ + else + { + /* Traditionally, we made sure 'int' was type 1, and builtin types + were defined to be sub-ranges of int. Unfortunately, this + does not allow us to distinguish true sub-ranges from integer + types. So, instead we define integer (non-sub-range) types as + sub-ranges of themselves. */ + dbxout_type_index (type); + } + if (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST) + fprintf (asmfile, ";%d", + TREE_INT_CST_LOW (TYPE_MIN_VALUE (type))); + else + fprintf (asmfile, ";0"); + if (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST) + fprintf (asmfile, ";%d;", + TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))); + else + fprintf (asmfile, ";-1;"); +} /* Output a reference to a type. If the type has not yet been described in the dbx output, output its definition now. @@ -851,6 +977,7 @@ dbxout_type (type, full, show_arg_types) int show_arg_types; { register tree tem; + static int anonymous_type_number = 0; /* If there was an input error and we don't really have a type, avoid crashing and write something that is at least valid @@ -859,10 +986,21 @@ dbxout_type (type, full, show_arg_types) type = integer_type_node; else { - type = TYPE_MAIN_VARIANT (type); + /* Try to find the "main variant" with the same name but not const + or volatile. (Since stabs does not distinguish const and volatile, + there is no need to make them separate types. But types with + different names are usefully distinguished.) */ + + for (tem = TYPE_MAIN_VARIANT (type); tem; tem = TYPE_NEXT_VARIANT (tem)) + if (!TYPE_READONLY (tem) && !TYPE_VOLATILE (tem) + && TYPE_NAME (tem) == TYPE_NAME (type)) + { + type = tem; + break; + } if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && DECL_IGNORED_P (TYPE_NAME (type))) + && TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (type))) full = 0; } @@ -875,15 +1013,24 @@ dbxout_type (type, full, show_arg_types) if (next_type_number == typevec_len) { - typevec = (enum typestatus *) xrealloc (typevec, typevec_len * 2 * sizeof typevec[0]); - bzero (typevec + typevec_len, typevec_len * sizeof typevec[0]); + typevec + = (struct typeinfo *) xrealloc (typevec, + typevec_len * 2 * sizeof typevec[0]); + bzero ((char *) (typevec + typevec_len), + typevec_len * sizeof typevec[0]); typevec_len *= 2; } + +#ifdef DBX_USE_BINCL + typevec[TYPE_SYMTAB_ADDRESS (type)].file_number + = current_file->file_number; + typevec[TYPE_SYMTAB_ADDRESS (type)].type_number + = current_file->next_type_number++; +#endif } /* Output the number of this type, to refer to it. */ - fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type)); - CHARS (3); + dbxout_type_index (type); #ifdef DBX_TYPE_DEFINED if (DBX_TYPE_DEFINED (type)) @@ -893,7 +1040,7 @@ dbxout_type (type, full, show_arg_types) /* If this type's definition has been output or is now being output, that is all. */ - switch (typevec[TYPE_SYMTAB_ADDRESS (type)]) + switch (typevec[TYPE_SYMTAB_ADDRESS (type)].status) { case TYPE_UNSEEN: break; @@ -914,14 +1061,24 @@ dbxout_type (type, full, show_arg_types) #ifdef DBX_NO_XREFS /* For systems where dbx output does not allow the `=xsNAME:' syntax, leave the type-number completely undefined rather than output - a cross-reference. */ - if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == ENUMERAL_TYPE) - - if ((TYPE_NAME (type) != 0 && !full) - || TYPE_SIZE (type) == 0) + a cross-reference. If we have already used GNU debug info extensions, + then it is OK to output a cross reference. This is necessary to get + proper C++ debug output. */ + if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE) + && ! use_gnu_debug_info_extensions) + /* We must use the same test here as we use twice below when deciding + whether to emit a cross-reference. */ + if ((TYPE_NAME (type) != 0 + && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_IGNORED_P (TYPE_NAME (type))) + && !full) + || TYPE_SIZE (type) == 0 + /* No way in DBX fmt to describe a variable size. */ + || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) { - typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF; + typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; return; } #endif @@ -934,7 +1091,14 @@ dbxout_type (type, full, show_arg_types) /* Mark it as defined, so that if it is self-referent we will not get into an infinite recursion of definitions. */ - typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_DEFINED; + typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_DEFINED; + + if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) + { + dbxout_type (DECL_ORIGINAL_TYPE (TYPE_NAME (type)), 0, 0); + return; + } switch (TREE_CODE (type)) { @@ -945,80 +1109,170 @@ dbxout_type (type, full, show_arg_types) without saying what it is. The debugger will make it a void type when the reference is seen, and nothing will ever override that default. */ - fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type)); - CHARS (3); + dbxout_type_index (type); break; case INTEGER_TYPE: if (type == char_type_node && ! TREE_UNSIGNED (type)) - /* Output the type `char' as a subrange of itself! - I don't understand this definition, just copied it - from the output of pcc. - This used to use `r2' explicitly and we used to - take care to make sure that `char' was type number 2. */ - fprintf (asmfile, "r%d;0;127;", TYPE_SYMTAB_ADDRESS (type)); -#ifdef WINNING_GDB - else if (TYPE_PRECISION (type) > BITS_PER_WORD) + { + /* Output the type `char' as a subrange of itself! + I don't understand this definition, just copied it + from the output of pcc. + This used to use `r2' explicitly and we used to + take care to make sure that `char' was type number 2. */ + fprintf (asmfile, "r"); + dbxout_type_index (type); + fprintf (asmfile, ";0;127;"); + } + else if (use_gnu_debug_info_extensions + && (TYPE_PRECISION (type) > TYPE_PRECISION (integer_type_node) + || TYPE_PRECISION (type) > HOST_BITS_PER_WIDE_INT)) { /* This used to say `r1' and we used to take care to make sure that `int' was type number 1. */ - fprintf (asmfile, "r%d;", TYPE_SYMTAB_ADDRESS (integer_type_node)); + fprintf (asmfile, "r"); + dbxout_type_index (integer_type_node); + fprintf (asmfile, ";"); print_int_cst_octal (TYPE_MIN_VALUE (type)); fprintf (asmfile, ";"); print_int_cst_octal (TYPE_MAX_VALUE (type)); fprintf (asmfile, ";"); } -#endif - else - /* Output other integer types as subranges of `int'. */ - /* This used to say `r1' and we used to take care - to make sure that `int' was type number 1. */ - fprintf (asmfile, "r%d;%d;%d;", - TYPE_SYMTAB_ADDRESS (integer_type_node), - TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)), - TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))); - CHARS (25); + else /* Output other integer types as subranges of `int'. */ + dbxout_range_type (type); + CHARS (22); break; case REAL_TYPE: /* This used to say `r1' and we used to take care to make sure that `int' was type number 1. */ - fprintf (asmfile, "r%d;%d;0;", TYPE_SYMTAB_ADDRESS (integer_type_node), - TREE_INT_CST_LOW (size_in_bytes (type))); - CHARS (16); + fprintf (asmfile, "r"); + dbxout_type_index (integer_type_node); + fprintf (asmfile, ";%d;0;", int_size_in_bytes (type)); + CHARS (13); + break; + + case CHAR_TYPE: + if (use_gnu_debug_info_extensions) + fprintf (asmfile, "@s%d;-20;", + BITS_PER_UNIT * int_size_in_bytes (type)); + else + { + /* Output the type `char' as a subrange of itself. + That is what pcc seems to do. */ + fprintf (asmfile, "r"); + dbxout_type_index (char_type_node); + fprintf (asmfile, ";0;%d;", TREE_UNSIGNED (type) ? 255 : 127); + } + CHARS (9); + break; + + case BOOLEAN_TYPE: + if (use_gnu_debug_info_extensions) + fprintf (asmfile, "@s%d;-16;", + BITS_PER_UNIT * int_size_in_bytes (type)); + else /* Define as enumeral type (False, True) */ + fprintf (asmfile, "eFalse:0,True:1,;"); + CHARS (17); + break; + + case FILE_TYPE: + putc ('d', asmfile); + CHARS (1); + dbxout_type (TREE_TYPE (type), 0, 0); + break; + + case COMPLEX_TYPE: + /* Differs from the REAL_TYPE by its new data type number */ + + if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE) + { + fprintf (asmfile, "r"); + dbxout_type_index (type); + fprintf (asmfile, ";%d;0;", + int_size_in_bytes (TREE_TYPE (type))); + CHARS (12); /* The number is probably incorrect here. */ + } + else + { + /* Output a complex integer type as a structure, + pending some other way to do it. */ + fprintf (asmfile, "s%d", int_size_in_bytes (type)); + + fprintf (asmfile, "real:"); + CHARS (10); + dbxout_type (TREE_TYPE (type), 0, 0); + fprintf (asmfile, ",%d,%d;", + 0, TYPE_PRECISION (TREE_TYPE (type))); + CHARS (8); + fprintf (asmfile, "imag:"); + CHARS (5); + dbxout_type (TREE_TYPE (type), 0, 0); + fprintf (asmfile, ",%d,%d;;", + TYPE_PRECISION (TREE_TYPE (type)), + TYPE_PRECISION (TREE_TYPE (type))); + CHARS (9); + } + break; + + case SET_TYPE: + if (use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + fprintf (asmfile, "@s%d;", + BITS_PER_UNIT * int_size_in_bytes (type)); + /* Check if a bitstring type, which in Chill is + different from a [power]set. */ + if (TYPE_STRING_FLAG (type)) + fprintf (asmfile, "@S;"); + } + putc ('S', asmfile); + CHARS (1); + dbxout_type (TYPE_DOMAIN (type), 0, 0); break; case ARRAY_TYPE: /* Output "a" followed by a range type definition for the index type of the array followed by a reference to the target-type. - ar1;0;N;M for an array of type M and size N. */ - /* This used to say `r1' and we used to take care - to make sure that `int' was type number 1. */ - fprintf (asmfile, "ar%d;0;%d;", TYPE_SYMTAB_ADDRESS (integer_type_node), - - (TYPE_DOMAIN (type) - ? TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) - : -1)); - CHARS (17); + ar1;0;N;M for a C array of type M and size N+1. */ + /* Check if a character string type, which in Chill is + different from an array of characters. */ + if (TYPE_STRING_FLAG (type) && use_gnu_debug_info_extensions) + { + have_used_extensions = 1; + fprintf (asmfile, "@S;"); + } + tem = TYPE_DOMAIN (type); + if (tem == NULL) + { + fprintf (asmfile, "ar"); + dbxout_type_index (integer_type_node); + fprintf (asmfile, ";0;-1;"); + } + else + { + fprintf (asmfile, "a"); + dbxout_range_type (tem); + } + CHARS (14); dbxout_type (TREE_TYPE (type), 0, 0); break; case RECORD_TYPE: case UNION_TYPE: + case QUAL_UNION_TYPE: { int i, n_baseclasses = 0; if (TYPE_BINFO (type) != 0 && TYPE_BINFO_BASETYPES (type) != 0) n_baseclasses = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)); - /* Output a structure type. */ + /* Output a structure type. We must use the same test here as we + use in the DBX_NO_XREFS case above. */ if ((TYPE_NAME (type) != 0 -#if 0 /* Tiemann says this creates output tha "confuses GDB". - Too bad the info is so vague. Hope this doesn't lose. */ && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL && DECL_IGNORED_P (TYPE_NAME (type))) -#endif && !full) || TYPE_SIZE (type) == 0 /* No way in DBX fmt to describe a variable size. */ @@ -1040,16 +1294,18 @@ dbxout_type (type, full, show_arg_types) if (TREE_CODE (TYPE_NAME (type)) != IDENTIFIER_NODE) abort (); #endif - dbxout_type_name (type); + if (TYPE_NAME (type) != 0) + dbxout_type_name (type); + else + fprintf (asmfile, "$$%d", anonymous_type_number++); fprintf (asmfile, ":"); - typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF; + typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; break; } - tem = size_in_bytes (type); /* Identify record or union, and print its size. */ fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "s%d" : "u%d", - TREE_INT_CST_LOW (tem)); + int_size_in_bytes (type)); if (use_gnu_debug_info_extensions) { @@ -1128,28 +1384,44 @@ dbxout_type (type, full, show_arg_types) break; case ENUMERAL_TYPE: - if ((TYPE_NAME (type) != 0 && !full - && (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && ! DECL_IGNORED_P (TYPE_NAME (type)))) + /* We must use the same test here as we use in the DBX_NO_XREFS case + above. We simplify it a bit since an enum will never have a variable + size. */ + if ((TYPE_NAME (type) != 0 + && ! (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_IGNORED_P (TYPE_NAME (type))) + && !full) || TYPE_SIZE (type) == 0) { fprintf (asmfile, "xe"); CHARS (3); dbxout_type_name (type); - typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF; + typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF; fprintf (asmfile, ":"); return; } #ifdef DBX_OUTPUT_ENUM DBX_OUTPUT_ENUM (asmfile, type); #else + if (use_gnu_debug_info_extensions + && TYPE_PRECISION (type) != TYPE_PRECISION (integer_type_node)) + fprintf (asmfile, "@s%d;", TYPE_PRECISION (type)); putc ('e', asmfile); CHARS (1); for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem)) { - fprintf (asmfile, "%s:%d,", IDENTIFIER_POINTER (TREE_PURPOSE (tem)), - TREE_INT_CST_LOW (TREE_VALUE (tem))); - CHARS (11 + IDENTIFIER_LENGTH (TREE_PURPOSE (tem))); + fprintf (asmfile, "%s:", IDENTIFIER_POINTER (TREE_PURPOSE (tem))); + if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == 0) + fprintf (asmfile, "%lu", + (unsigned long) TREE_INT_CST_LOW (TREE_VALUE (tem))); + else if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == -1 + && TREE_INT_CST_LOW (TREE_VALUE (tem)) < 0) + fprintf (asmfile, "%ld", + (long) TREE_INT_CST_LOW (TREE_VALUE (tem))); + else + print_int_cst_octal (TREE_VALUE (tem)); + fprintf (asmfile, ","); + CHARS (20 + IDENTIFIER_LENGTH (TREE_PURPOSE (tem))); if (TREE_CHAIN (tem) != 0) CONTIN; } @@ -1175,6 +1447,7 @@ dbxout_type (type, full, show_arg_types) /* Normally, just output the return type. The argument types are encoded in the method name. */ putc ('#', asmfile); + CHARS (1); dbxout_type (TREE_TYPE (type), 0, 0); putc (';', asmfile); CHARS (1); @@ -1247,6 +1520,19 @@ print_int_cst_octal (c) unsigned HOST_WIDE_INT high = TREE_INT_CST_HIGH (c); unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (c); int excess = (3 - (HOST_BITS_PER_WIDE_INT % 3)); + int width = TYPE_PRECISION (TREE_TYPE (c)); + + /* GDB wants constants with no extra leading "1" bits, so + we need to remove any sign-extension that might be + present. */ + if (width == HOST_BITS_PER_WIDE_INT * 2) + ; + else if (width > HOST_BITS_PER_WIDE_INT) + high &= (((HOST_WIDE_INT) 1 << (width - HOST_BITS_PER_WIDE_INT)) - 1); + else if (width == HOST_BITS_PER_WIDE_INT) + high = 0; + else + high = 0, low &= (((HOST_WIDE_INT) 1 << width) - 1); fprintf (asmfile, "0"); @@ -1262,7 +1548,10 @@ print_int_cst_octal (c) = ((high & (((HOST_WIDE_INT) 1 << excess) - 1)) << (3 - excess) | (low >> (HOST_BITS_PER_WIDE_INT / 3 * 3))); unsigned HOST_WIDE_INT end - = low & (((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 3 * 3)) - 1); + = low & (((unsigned HOST_WIDE_INT) 1 + << (HOST_BITS_PER_WIDE_INT / 3 * 3)) + - 1); + fprintf (asmfile, "%o%01o", beg, middle); print_octal (end, HOST_BITS_PER_WIDE_INT / 3); } @@ -1315,10 +1604,8 @@ dbxout_symbol (decl, local) tree decl; int local; { - int letter = 0; tree type = TREE_TYPE (decl); tree context = NULL_TREE; - int regno = -1; /* Cast avoids warning in old compilers. */ current_sym_code = (STAB_CODE_TYPE) 0; @@ -1391,19 +1678,20 @@ dbxout_symbol (decl, local) /* If this typedef name was defined by outputting the type, don't duplicate it. */ - if (typevec[TYPE_SYMTAB_ADDRESS (type)] == TYPE_DEFINED + if (typevec[TYPE_SYMTAB_ADDRESS (type)].status == TYPE_DEFINED && TYPE_NAME (TREE_TYPE (decl)) == decl) return; #endif /* Don't output the same typedef twice. And don't output what language-specific stuff doesn't want output. */ - if (TREE_ASM_WRITTEN (decl) || DECL_IGNORED_P (decl)) + if (TREE_ASM_WRITTEN (decl) || TYPE_DECL_SUPPRESS_DEBUG (decl)) return; FORCE_TEXT; { int tag_needed = 1; + int did_output = 0; if (DECL_NAME (decl)) { @@ -1413,14 +1701,16 @@ dbxout_symbol (decl, local) /* Handle the case of a C++ structure or union where the TYPE_NAME is a TYPE_DECL which gives both a typedef name and a tag. */ - /* dbx requires the tag first and the typedef second. - ??? there is a bug here. It generates spurious tags - for C code. */ + /* dbx requires the tag first and the typedef second. */ if ((TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == UNION_TYPE) + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) && TYPE_NAME (type) == decl && !(use_gnu_debug_info_extensions && have_used_extensions) - && !TREE_ASM_WRITTEN (TYPE_NAME (type))) + && !TREE_ASM_WRITTEN (TYPE_NAME (type)) + /* Distinguish the implicit typedefs of C++ + from explicit ones that might be found in C. */ + && DECL_ARTIFICIAL (decl)) { tree name = TYPE_NAME (type); if (TREE_CODE (name) == TYPE_DECL) @@ -1443,8 +1733,12 @@ dbxout_symbol (decl, local) /* Short cut way to output a tag also. */ if ((TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == UNION_TYPE) - && TYPE_NAME (type) == decl) + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + && TYPE_NAME (type) == decl + /* Distinguish the implicit typedefs of C++ + from explicit ones that might be found in C. */ + && DECL_ARTIFICIAL (decl)) { if (use_gnu_debug_info_extensions && have_used_extensions) { @@ -1462,9 +1756,16 @@ dbxout_symbol (decl, local) dbxout_type (type, 1, 0); dbxout_finish_symbol (decl); + did_output = 1; } + /* Don't output a tag if this is an incomplete type (TYPE_SIZE is + zero). This prevents the sun4 Sun OS 4.x dbx from crashing. */ + if (tag_needed && TYPE_NAME (type) != 0 + && (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE + || (DECL_NAME (TYPE_NAME (type)) != 0)) + && TYPE_SIZE (type) != 0 && !TREE_ASM_WRITTEN (TYPE_NAME (type))) { /* For a TYPE_DECL with no name, but the type has a name, @@ -1485,6 +1786,24 @@ dbxout_symbol (decl, local) IDENTIFIER_POINTER (name)); dbxout_type (type, 1, 0); dbxout_finish_symbol (NULL_TREE); + did_output = 1; + } + + /* If an enum type has no name, it cannot be referred to, + but we must output it anyway, since the enumeration constants + can be referred to. */ + if (!did_output && TREE_CODE (type) == ENUMERAL_TYPE) + { + current_sym_code = DBX_TYPE_DECL_STABS_CODE; + current_sym_value = 0; + current_sym_addr = 0; + current_sym_nchars = 2; + + /* Some debuggers fail when given NULL names, so give this a + harmless name of ` '. */ + fprintf (asmfile, "%s \" :T", ASM_STABS_OP); + dbxout_type (type, 1, 0); + dbxout_finish_symbol (NULL_TREE); } /* Prevent duplicate output of a typedef. */ @@ -1540,194 +1859,248 @@ dbxout_symbol (decl, local) /* else it is something we handle like a normal variable. */ } - DECL_RTL (decl) = eliminate_regs (DECL_RTL (decl), 0, 0); + DECL_RTL (decl) = eliminate_regs (DECL_RTL (decl), 0, NULL_RTX, 0); #ifdef LEAF_REG_REMAP if (leaf_function) leaf_renumber_regs_insn (DECL_RTL (decl)); #endif - /* Don't mention a variable at all - if it was completely optimized into nothingness. + dbxout_symbol_location (decl, type, 0, DECL_RTL (decl)); + } +} + +/* Output the stab for DECL, a VAR_DECL, RESULT_DECL or PARM_DECL. + Add SUFFIX to its name, if SUFFIX is not 0. + Describe the variable as residing in HOME + (usually HOME is DECL_RTL (DECL), but not always). */ + +static void +dbxout_symbol_location (decl, type, suffix, home) + tree decl, type; + char *suffix; + rtx home; +{ + int letter = 0; + int regno = -1; - If DECL was from an inline function, then it's rtl - is not identically the rtl that was used in this - particular compilation. */ - if (GET_CODE (DECL_RTL (decl)) == REG) + /* Don't mention a variable at all + if it was completely optimized into nothingness. + + If the decl was from an inline function, then it's rtl + is not identically the rtl that was used in this + particular compilation. */ + if (GET_CODE (home) == REG) + { + regno = REGNO (home); + if (regno >= FIRST_PSEUDO_REGISTER) + return; + } + else if (GET_CODE (home) == SUBREG) + { + rtx value = home; + int offset = 0; + while (GET_CODE (value) == SUBREG) + { + offset += SUBREG_WORD (value); + value = SUBREG_REG (value); + } + if (GET_CODE (value) == REG) { - regno = REGNO (DECL_RTL (decl)); + regno = REGNO (value); if (regno >= FIRST_PSEUDO_REGISTER) return; + regno += offset; } - else if (GET_CODE (DECL_RTL (decl)) == SUBREG) + alter_subreg (home); + } + + /* The kind-of-variable letter depends on where + the variable is and on the scope of its name: + G and N_GSYM for static storage and global scope, + S for static storage and file scope, + V for static storage and local scope, + for those two, use N_LCSYM if data is in bss segment, + N_STSYM if in data segment, N_FUN otherwise. + (We used N_FUN originally, then changed to N_STSYM + to please GDB. However, it seems that confused ld. + Now GDB has been fixed to like N_FUN, says Kingdon.) + no letter at all, and N_LSYM, for auto variable, + r and N_RSYM for register variable. */ + + if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == SYMBOL_REF) + { + if (TREE_PUBLIC (decl)) { - rtx value = DECL_RTL (decl); - int offset = 0; - while (GET_CODE (value) == SUBREG) - { - offset += SUBREG_WORD (value); - value = SUBREG_REG (value); - } - if (GET_CODE (value) == REG) - { - regno = REGNO (value); - if (regno >= FIRST_PSEUDO_REGISTER) - return; - regno += offset; - } - alter_subreg (DECL_RTL (decl)); + letter = 'G'; + current_sym_code = N_GSYM; } - - /* The kind-of-variable letter depends on where - the variable is and on the scope of its name: - G and N_GSYM for static storage and global scope, - S for static storage and file scope, - V for static storage and local scope, - for those two, use N_LCSYM if data is in bss segment, - N_STSYM if in data segment, N_FUN otherwise. - (We used N_FUN originally, then changed to N_STSYM - to please GDB. However, it seems that confused ld. - Now GDB has been fixed to like N_FUN, says Kingdon.) - no letter at all, and N_LSYM, for auto variable, - r and N_RSYM for register variable. */ - - if (GET_CODE (DECL_RTL (decl)) == MEM - && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF) + else { - if (TREE_PUBLIC (decl)) - { - letter = 'G'; - current_sym_code = N_GSYM; - } + current_sym_addr = XEXP (home, 0); + + letter = decl_function_context (decl) ? 'V' : 'S'; + + /* This should be the same condition as in assemble_variable, but + we don't have access to dont_output_data here. So, instead, + we rely on the fact that error_mark_node initializers always + end up in bss for C++ and never end up in bss for C. */ + if (DECL_INITIAL (decl) == 0 + || (!strcmp (lang_identify (), "cplusplus") + && DECL_INITIAL (decl) == error_mark_node)) + current_sym_code = N_LCSYM; + else if (DECL_IN_TEXT_SECTION (decl)) + /* This is not quite right, but it's the closest + of all the codes that Unix defines. */ + current_sym_code = DBX_STATIC_CONST_VAR_CODE; else { - current_sym_addr = XEXP (DECL_RTL (decl), 0); - - letter = decl_function_context (decl) ? 'V' : 'S'; - - if (!DECL_INITIAL (decl)) - current_sym_code = N_LCSYM; - else if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl)) - /* This is not quite right, but it's the closest - of all the codes that Unix defines. */ - current_sym_code = DBX_STATIC_CONST_VAR_CODE; - else - { -/* Ultrix `as' seems to need this. */ + /* Ultrix `as' seems to need this. */ #ifdef DBX_STATIC_STAB_DATA_SECTION - data_section (); + data_section (); #endif - current_sym_code = N_STSYM; - } + current_sym_code = N_STSYM; } } - else if (regno >= 0) + } + else if (regno >= 0) + { + letter = 'r'; + current_sym_code = N_RSYM; + current_sym_value = DBX_REGISTER_NUMBER (regno); + } + else if (GET_CODE (home) == MEM + && (GET_CODE (XEXP (home, 0)) == MEM + || (GET_CODE (XEXP (home, 0)) == REG + && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM))) + /* If the value is indirect by memory or by a register + that isn't the frame pointer + then it means the object is variable-sized and address through + that register or stack slot. DBX has no way to represent this + so all we can do is output the variable as a pointer. + If it's not a parameter, ignore it. + (VAR_DECLs like this can be made by integrate.c.) */ + { + if (GET_CODE (XEXP (home, 0)) == REG) { letter = 'r'; current_sym_code = N_RSYM; - current_sym_value = DBX_REGISTER_NUMBER (regno); + current_sym_value = DBX_REGISTER_NUMBER (REGNO (XEXP (home, 0))); } - else if (GET_CODE (DECL_RTL (decl)) == MEM - && (GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM - || (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG - && REGNO (XEXP (DECL_RTL (decl), 0)) != FRAME_POINTER_REGNUM))) - /* If the value is indirect by memory or by a register - that isn't the frame pointer - then it means the object is variable-sized and address through - that register or stack slot. DBX has no way to represent this - so all we can do is output the variable as a pointer. - If it's not a parameter, ignore it. - (VAR_DECLs like this can be made by integrate.c.) */ - { - if (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG) - { - letter = 'r'; - current_sym_code = N_RSYM; - current_sym_value = DBX_REGISTER_NUMBER (REGNO (XEXP (DECL_RTL (decl), 0))); - } - else - { - current_sym_code = N_LSYM; - /* DECL_RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). - We want the value of that CONST_INT. */ - current_sym_value - = DEBUGGER_AUTO_OFFSET (XEXP (XEXP (DECL_RTL (decl), 0), 0)); - } - - /* Effectively do build_pointer_type, but don't cache this type, - since it might be temporary whereas the type it points to - might have been saved for inlining. */ - /* Don't use REFERENCE_TYPE because dbx can't handle that. */ - type = make_node (POINTER_TYPE); - TREE_TYPE (type) = TREE_TYPE (decl); - } - else if (GET_CODE (DECL_RTL (decl)) == MEM - && GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG) - { - current_sym_code = N_LSYM; - current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (DECL_RTL (decl), 0)); - } - else if (GET_CODE (DECL_RTL (decl)) == MEM - && GET_CODE (XEXP (DECL_RTL (decl), 0)) == PLUS - && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 1)) == CONST_INT) + else { current_sym_code = N_LSYM; - /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) + /* RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). We want the value of that CONST_INT. */ - current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (DECL_RTL (decl), 0)); - } - else if (GET_CODE (DECL_RTL (decl)) == MEM - && GET_CODE (XEXP (DECL_RTL (decl), 0)) == CONST) - { - /* Handle an obscure case which can arise when optimizing and - when there are few available registers. (This is *always* - the case for i386/i486 targets). The DECL_RTL looks like - (MEM (CONST ...)) even though this variable is a local `auto' - or a local `register' variable. In effect, what has happened - is that the reload pass has seen that all assignments and - references for one such a local variable can be replaced by - equivalent assignments and references to some static storage - variable, thereby avoiding the need for a register. In such - cases we're forced to lie to debuggers and tell them that - this variable was itself `static'. */ - current_sym_code = N_LCSYM; - letter = 'V'; - current_sym_addr = XEXP (XEXP (DECL_RTL (decl), 0), 0); + current_sym_value + = DEBUGGER_AUTO_OFFSET (XEXP (XEXP (home, 0), 0)); } + + /* Effectively do build_pointer_type, but don't cache this type, + since it might be temporary whereas the type it points to + might have been saved for inlining. */ + /* Don't use REFERENCE_TYPE because dbx can't handle that. */ + type = make_node (POINTER_TYPE); + TREE_TYPE (type) = TREE_TYPE (decl); + } + else if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == REG) + { + current_sym_code = N_LSYM; + current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); + } + else if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == PLUS + && GET_CODE (XEXP (XEXP (home, 0), 1)) == CONST_INT) + { + current_sym_code = N_LSYM; + /* RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) + We want the value of that CONST_INT. */ + current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (home, 0)); + } + else if (GET_CODE (home) == MEM + && GET_CODE (XEXP (home, 0)) == CONST) + { + /* Handle an obscure case which can arise when optimizing and + when there are few available registers. (This is *always* + the case for i386/i486 targets). The RTL looks like + (MEM (CONST ...)) even though this variable is a local `auto' + or a local `register' variable. In effect, what has happened + is that the reload pass has seen that all assignments and + references for one such a local variable can be replaced by + equivalent assignments and references to some static storage + variable, thereby avoiding the need for a register. In such + cases we're forced to lie to debuggers and tell them that + this variable was itself `static'. */ + current_sym_code = N_LCSYM; + letter = 'V'; + current_sym_addr = XEXP (XEXP (home, 0), 0); + } + else if (GET_CODE (home) == CONCAT) + { + tree subtype = TREE_TYPE (type); + + /* If the variable's storage is in two parts, + output each as a separate stab with a modified name. */ + if (WORDS_BIG_ENDIAN) + dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 0)); else - /* Address might be a MEM, when DECL is a variable-sized object. - Or it might be const0_rtx, meaning previous passes - want us to ignore this variable. */ - break; + dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 0)); - /* Ok, start a symtab entry and output the variable name. */ - FORCE_TEXT; + /* Cast avoids warning in old compilers. */ + current_sym_code = (STAB_CODE_TYPE) 0; + current_sym_value = 0; + current_sym_addr = 0; + dbxout_prepare_symbol (decl); + + if (WORDS_BIG_ENDIAN) + dbxout_symbol_location (decl, subtype, "$real", XEXP (home, 1)); + else + dbxout_symbol_location (decl, subtype, "$imag", XEXP (home, 1)); + return; + } + else + /* Address might be a MEM, when DECL is a variable-sized object. + Or it might be const0_rtx, meaning previous passes + want us to ignore this variable. */ + return; + + /* Ok, start a symtab entry and output the variable name. */ + FORCE_TEXT; #ifdef DBX_STATIC_BLOCK_START - DBX_STATIC_BLOCK_START (asmfile, current_sym_code); + DBX_STATIC_BLOCK_START (asmfile, current_sym_code); #endif - /* One slight hitch: if this is a VAR_DECL which is a static - class member, we must put out the mangled name instead of the - DECL_NAME. */ - { - char *name; - /* Note also that static member (variable) names DO NOT begin - with underscores in .stabs directives. */ - if (DECL_LANG_SPECIFIC (decl)) - name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - else - name = IDENTIFIER_POINTER (DECL_NAME (decl)); - fprintf (asmfile, "%s \"%s:", ASM_STABS_OP, name); - } - if (letter) putc (letter, asmfile); - dbxout_type (type, 0, 0); - dbxout_finish_symbol (decl); + dbxout_symbol_name (decl, suffix, letter); + dbxout_type (type, 0, 0); + dbxout_finish_symbol (decl); #ifdef DBX_STATIC_BLOCK_END - DBX_STATIC_BLOCK_END (asmfile, current_sym_code); + DBX_STATIC_BLOCK_END (asmfile, current_sym_code); #endif - break; - } +} + +/* Output the symbol name of DECL for a stabs, with suffix SUFFIX. + Then output LETTER to indicate the kind of location the symbol has. */ + +static void +dbxout_symbol_name (decl, suffix, letter) + tree decl; + char *suffix; + int letter; +{ + /* One slight hitch: if this is a VAR_DECL which is a static + class member, we must put out the mangled name instead of the + DECL_NAME. Note also that static member (variable) names DO NOT begin + with underscores in .stabs directives. */ + char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + if (name == 0) + name = "(anon)"; + fprintf (asmfile, "%s \"%s%s:", ASM_STABS_OP, name, + (suffix ? suffix : "")); + + if (letter) putc (letter, asmfile); } static void @@ -1749,10 +2122,8 @@ dbxout_finish_symbol (sym) DBX_FINISH_SYMBOL (sym); #else int line = 0; -#ifdef WINNING_GDB - if (sym != 0) + if (use_gnu_debug_info_extensions && sym != 0) line = DECL_SOURCE_LINE (sym); -#endif fprintf (asmfile, "\",%d,0,%d,", current_sym_code, line); if (current_sym_addr) @@ -1800,8 +2171,8 @@ dbxout_parms (parms) /* Perform any necessary register eliminations on the parameter's rtl, so that the debugging output will be accurate. */ DECL_INCOMING_RTL (parms) - = eliminate_regs (DECL_INCOMING_RTL (parms), 0, NULL_RTX); - DECL_RTL (parms) = eliminate_regs (DECL_RTL (parms), 0, NULL_RTX); + = eliminate_regs (DECL_INCOMING_RTL (parms), 0, NULL_RTX, 0); + DECL_RTL (parms) = eliminate_regs (DECL_RTL (parms), 0, NULL_RTX, 0); #ifdef LEAF_REG_REMAP if (leaf_function) { @@ -1843,37 +2214,7 @@ dbxout_parms (parms) DBX_MEMPARM_STABS_LETTER); } - if (GET_CODE (DECL_RTL (parms)) == REG - && REGNO (DECL_RTL (parms)) >= 0 - && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) - dbxout_type (DECL_ARG_TYPE (parms), 0, 0); - else - { - int original_value = current_sym_value; - - /* This is the case where the parm is passed as an int or double - and it is converted to a char, short or float and stored back - in the parmlist. In this case, describe the parm - with the variable's declared type, and adjust the address - if the least significant bytes (which we are using) are not - the first ones. */ -#if BYTES_BIG_ENDIAN - if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms)) - current_sym_value += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms))) - - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms)))); -#endif - - if (GET_CODE (DECL_RTL (parms)) == MEM - && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS - && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT - && INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == current_sym_value) - dbxout_type (TREE_TYPE (parms), 0, 0); - else - { - current_sym_value = original_value; - dbxout_type (DECL_ARG_TYPE (parms), 0, 0); - } - } + dbxout_type (DECL_ARG_TYPE (parms), 0, 0); current_sym_value = DEBUGGER_ARG_OFFSET (current_sym_value, addr); dbxout_finish_symbol (parms); } @@ -1881,6 +2222,7 @@ dbxout_parms (parms) { rtx best_rtl; char regparm_letter; + tree parm_type; /* Parm passed in registers and lives in registers or nowhere. */ current_sym_code = DBX_REGPARM_STABS_CODE; @@ -1890,14 +2232,23 @@ dbxout_parms (parms) /* If parm lives in a register, use that register; pretend the parm was passed there. It would be more consistent to describe the register where the parm was passed, - but in practice that register usually holds something else. */ + but in practice that register usually holds something else. + + If we use DECL_RTL, then we must use the declared type of + the variable, not the type that it arrived in. */ if (REGNO (DECL_RTL (parms)) >= 0 && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) - best_rtl = DECL_RTL (parms); - /* If the parm lives nowhere, - use the register where it was passed. */ + { + best_rtl = DECL_RTL (parms); + parm_type = TREE_TYPE (parms); + } + /* If the parm lives nowhere, use the register where it was + passed. It is also better to use the declared type here. */ else - best_rtl = DECL_INCOMING_RTL (parms); + { + best_rtl = DECL_INCOMING_RTL (parms); + parm_type = TREE_TYPE (parms); + } current_sym_value = DBX_REGISTER_NUMBER (REGNO (best_rtl)); FORCE_TEXT; @@ -1915,13 +2266,17 @@ dbxout_parms (parms) regparm_letter); } - dbxout_type (DECL_ARG_TYPE (parms), 0, 0); + dbxout_type (parm_type, 0, 0); dbxout_finish_symbol (parms); } else if (GET_CODE (DECL_RTL (parms)) == MEM && GET_CODE (XEXP (DECL_RTL (parms), 0)) == REG - && rtx_equal_p (XEXP (DECL_RTL (parms), 0), - DECL_INCOMING_RTL (parms))) + && REGNO (XEXP (DECL_RTL (parms), 0)) != HARD_FRAME_POINTER_REGNUM + && REGNO (XEXP (DECL_RTL (parms), 0)) != STACK_POINTER_REGNUM +#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM + && REGNO (XEXP (DECL_RTL (parms), 0)) != ARG_POINTER_REGNUM +#endif + ) { /* Parm was passed via invisible reference. That is, its address was passed in a register. @@ -1933,10 +2288,20 @@ dbxout_parms (parms) /* Parm passed in registers and lives in registers or nowhere. */ current_sym_code = DBX_REGPARM_STABS_CODE; - regparm_letter = DBX_REGPARM_STABS_LETTER; + if (use_gnu_debug_info_extensions) + regparm_letter = GDB_INV_REF_REGPARM_STABS_LETTER; + else + regparm_letter = DBX_REGPARM_STABS_LETTER; + + /* DECL_RTL looks like (MEM (REG...). Get the register number. + If it is an unallocated pseudo-reg, then use the register where + it was passed instead. */ + if (REGNO (XEXP (DECL_RTL (parms), 0)) >= 0 + && REGNO (XEXP (DECL_RTL (parms), 0)) < FIRST_PSEUDO_REGISTER) + current_sym_value = REGNO (XEXP (DECL_RTL (parms), 0)); + else + current_sym_value = REGNO (DECL_INCOMING_RTL (parms)); - /* DECL_RTL looks like (MEM (REG...). Get the register number. */ - current_sym_value = REGNO (XEXP (DECL_RTL (parms), 0)); current_sym_addr = 0; FORCE_TEXT; @@ -1946,20 +2311,24 @@ dbxout_parms (parms) fprintf (asmfile, "%s \"%s:%c", ASM_STABS_OP, IDENTIFIER_POINTER (DECL_NAME (parms)), - DBX_REGPARM_STABS_LETTER); + regparm_letter); } else { current_sym_nchars = 8; fprintf (asmfile, "%s \"(anon):%c", ASM_STABS_OP, - DBX_REGPARM_STABS_LETTER); + regparm_letter); } dbxout_type (TREE_TYPE (parms), 0, 0); dbxout_finish_symbol (parms); } else if (GET_CODE (DECL_RTL (parms)) == MEM - && XEXP (DECL_RTL (parms), 0) != const0_rtx) + && XEXP (DECL_RTL (parms), 0) != const0_rtx + /* ??? A constant address for a parm can happen + when the reg it lives in is equiv to a constant in memory. + Should make this not happen, after 2.4. */ + && ! CONSTANT_P (XEXP (DECL_RTL (parms), 0))) { /* Parm was passed in registers but lives on the stack. */ @@ -2016,7 +2385,7 @@ dbxout_reg_parms (parms) tree parms; { for (; parms; parms = TREE_CHAIN (parms)) - if (DECL_NAME (parms)) + if (DECL_NAME (parms) && PARM_PASSED_IN_MEMORY (parms)) { dbxout_prepare_symbol (parms); @@ -2024,65 +2393,17 @@ dbxout_reg_parms (parms) but were passed in memory. */ if (GET_CODE (DECL_RTL (parms)) == REG && REGNO (DECL_RTL (parms)) >= 0 - && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER - && PARM_PASSED_IN_MEMORY (parms)) - { - current_sym_code = N_RSYM; - current_sym_value = DBX_REGISTER_NUMBER (REGNO (DECL_RTL (parms))); - current_sym_addr = 0; - - FORCE_TEXT; - if (DECL_NAME (parms)) - { - current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms)); - fprintf (asmfile, "%s \"%s:r", ASM_STABS_OP, - IDENTIFIER_POINTER (DECL_NAME (parms))); - } - else - { - current_sym_nchars = 8; - fprintf (asmfile, "%s \"(anon):r", ASM_STABS_OP); - } - dbxout_type (TREE_TYPE (parms), 0, 0); - dbxout_finish_symbol (parms); - } + && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) + dbxout_symbol_location (parms, TREE_TYPE (parms), + 0, DECL_RTL (parms)); + else if (GET_CODE (DECL_RTL (parms)) == CONCAT) + dbxout_symbol_location (parms, TREE_TYPE (parms), + 0, DECL_RTL (parms)); /* Report parms that live in memory but not where they were passed. */ else if (GET_CODE (DECL_RTL (parms)) == MEM - && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS - && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT - && PARM_PASSED_IN_MEMORY (parms) && ! rtx_equal_p (DECL_RTL (parms), DECL_INCOMING_RTL (parms))) - { -#if 0 /* ??? It is not clear yet what should replace this. */ - int offset = DECL_OFFSET (parms) / BITS_PER_UNIT; - /* A parm declared char is really passed as an int, - so it occupies the least significant bytes. - On a big-endian machine those are not the low-numbered ones. */ -#if BYTES_BIG_ENDIAN - if (offset != -1 && TREE_TYPE (parms) != DECL_ARG_TYPE (parms)) - offset += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms))) - - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms)))); -#endif - if (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) != offset) {...} -#endif - current_sym_code = N_LSYM; - current_sym_value = DEBUGGER_AUTO_OFFSET (XEXP (DECL_RTL (parms), 0)); - current_sym_addr = 0; - FORCE_TEXT; - if (DECL_NAME (parms)) - { - current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms)); - fprintf (asmfile, "%s \"%s:", ASM_STABS_OP, - IDENTIFIER_POINTER (DECL_NAME (parms))); - } - else - { - current_sym_nchars = 8; - fprintf (asmfile, "%s \"(anon):", ASM_STABS_OP); - } - dbxout_type (TREE_TYPE (parms), 0, 0); - dbxout_finish_symbol (parms); - } + dbxout_symbol_location (parms, TREE_TYPE (parms), + 0, DECL_RTL (parms)); } } @@ -2193,7 +2514,7 @@ dbxout_block (block, depth, args) assemble_name (asmfile, buf); #if DBX_BLOCKS_FUNCTION_RELATIVE fputc ('-', asmfile); - assemble_name (asmfile, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl))); + assemble_name (asmfile, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); #endif fprintf (asmfile, "\n"); #endif @@ -2226,7 +2547,7 @@ dbxout_block (block, depth, args) assemble_name (asmfile, buf); #if DBX_BLOCKS_FUNCTION_RELATIVE fputc ('-', asmfile); - assemble_name (asmfile, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl))); + assemble_name (asmfile, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); #endif fprintf (asmfile, "\n"); #endif @@ -2278,5 +2599,13 @@ dbxout_function (decl) #ifdef DBX_OUTPUT_FUNCTION_END DBX_OUTPUT_FUNCTION_END (asmfile, decl); #endif +#if defined(ASM_OUTPUT_SECTION_NAME) + if (use_gnu_debug_info_extensions +#if defined(NO_DBX_FUNCTION_END) + && ! NO_DBX_FUNCTION_END +#endif + ) + dbxout_function_end (); +#endif } #endif /* DBX_DEBUGGING_INFO */