1644 lines
47 KiB
C
1644 lines
47 KiB
C
|
/* Output dbx-format symbol table information from GNU compiler.
|
|||
|
Copyright (C) 1987, 1988 Free Software Foundation, Inc.
|
|||
|
|
|||
|
This file is part of GNU CC.
|
|||
|
|
|||
|
GNU CC is free software; you can redistribute it and/or modify
|
|||
|
it under the terms of the GNU General Public License as published by
|
|||
|
the Free Software Foundation; either version 1, or (at your option)
|
|||
|
any later version.
|
|||
|
|
|||
|
GNU CC is distributed in the hope that it will be useful,
|
|||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
GNU General Public License for more details.
|
|||
|
|
|||
|
You should have received a copy of the GNU General Public License
|
|||
|
along with GNU CC; see the file COPYING. If not, write to
|
|||
|
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
|
|
|||
|
|
|||
|
/* Output dbx-format symbol table data.
|
|||
|
This consists of many symbol table entries, each of them
|
|||
|
a .stabs assembler pseudo-op with four operands:
|
|||
|
a "name" which is really a description of one symbol and its type,
|
|||
|
a "code", which is a symbol defined in stab.h whose name starts with N_,
|
|||
|
an unused operand always 0,
|
|||
|
and a "value" which is an address or an offset.
|
|||
|
The name is enclosed in doublequote characters.
|
|||
|
|
|||
|
Each function, variable, typedef, and structure tag
|
|||
|
has a symbol table entry to define it.
|
|||
|
The beginning and end of each level of name scoping within
|
|||
|
a function are also marked by special symbol table entries.
|
|||
|
|
|||
|
The "name" consists of the symbol name, a colon, a kind-of-symbol letter,
|
|||
|
and a data type number. The data type number may be followed by
|
|||
|
"=" and a type definition; normally this will happen the first time
|
|||
|
the type number is mentioned. The type definition may refer to
|
|||
|
other types by number, and those type numbers may be followed
|
|||
|
by "=" and nested definitions.
|
|||
|
|
|||
|
This can make the "name" quite long.
|
|||
|
When a name is more than 80 characters, we split the .stabs pseudo-op
|
|||
|
into two .stabs pseudo-ops, both sharing the same "code" and "value".
|
|||
|
The first one is marked as continued with a double-backslash at the
|
|||
|
end of its "name".
|
|||
|
|
|||
|
The kind-of-symbol letter distinguished function names from global
|
|||
|
variables from file-scope variables from parameters from auto
|
|||
|
variables in memory from typedef names from register variables.
|
|||
|
See `dbxout_symbol'.
|
|||
|
|
|||
|
The "code" is mostly redundant with the kind-of-symbol letter
|
|||
|
that goes in the "name", but not entirely: for symbols located
|
|||
|
in static storage, the "code" says which segment the address is in,
|
|||
|
which controls how it is relocated.
|
|||
|
|
|||
|
The "value" for a symbol in static storage
|
|||
|
is the core address of the symbol (actually, the assembler
|
|||
|
label for the symbol). For a symbol located in a stack slot
|
|||
|
it is the stack offset; for one in a register, the register number.
|
|||
|
For a typedef symbol, it is zero.
|
|||
|
|
|||
|
If DEBUG_SYMS_TEXT is defined, all debugging symbols must be
|
|||
|
output while in the text section.
|
|||
|
|
|||
|
For more on data type definitions, see `dbxout_type'. */
|
|||
|
|
|||
|
#include "config.h"
|
|||
|
#include "tree.h"
|
|||
|
#include "cplus-tree.h"
|
|||
|
#include "rtl.h"
|
|||
|
#include "flags.h"
|
|||
|
#include <stdio.h>
|
|||
|
#include "regs.h"
|
|||
|
|
|||
|
/* Typical USG systems don't have stab.h, and they also have
|
|||
|
no use for DBX-format debugging info. */
|
|||
|
|
|||
|
#ifdef DBX_DEBUGGING_INFO
|
|||
|
|
|||
|
#ifdef DEBUG_SYMS_TEXT
|
|||
|
#define FORCE_TEXT text_section ();
|
|||
|
#else
|
|||
|
#define FORCE_TEXT
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef USG
|
|||
|
#include "stab.h" /* If doing DBX on sysV, use our own stab.h. */
|
|||
|
#else
|
|||
|
#include <stab.h> /* On BSD, use the system's stab.h. */
|
|||
|
#endif /* not USG */
|
|||
|
|
|||
|
/* Stream for writing to assembler file. */
|
|||
|
|
|||
|
static FILE *asmfile;
|
|||
|
|
|||
|
enum typestatus {TYPE_UNSEEN, TYPE_XREF, TYPE_DEFINED};
|
|||
|
|
|||
|
/* Vector recording the status of describing 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. */
|
|||
|
|
|||
|
enum typestatus *typevec;
|
|||
|
|
|||
|
/* Number of elements of space allocated in `typevec'. */
|
|||
|
|
|||
|
static int typevec_len;
|
|||
|
|
|||
|
/* In dbx output, each type gets a unique number.
|
|||
|
This is the number for the next type output.
|
|||
|
The number, once assigned, is in the TYPE_SYMTAB_ADDRESS field. */
|
|||
|
|
|||
|
static int next_type_number;
|
|||
|
|
|||
|
/* 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
|
|||
|
end of the ranges of code in each block
|
|||
|
with assembler labels LBBn and LBEn, where n is the block number.
|
|||
|
The labels are generated in final, which assigns numbers to the
|
|||
|
blocks in the same way. */
|
|||
|
|
|||
|
static int next_block_number;
|
|||
|
|
|||
|
/* These variables are for dbxout_symbol to communicate to
|
|||
|
dbxout_finish_symbol.
|
|||
|
current_sym_code is the symbol-type-code, a symbol N_... define in stab.h.
|
|||
|
current_sym_value and current_sym_addr are two ways to address the
|
|||
|
value to store in the symtab entry.
|
|||
|
current_sym_addr if nonzero represents the value as an rtx.
|
|||
|
If that is zero, current_sym_value is used. This is used
|
|||
|
when the value is an offset (such as for auto variables,
|
|||
|
register variables and parms). */
|
|||
|
|
|||
|
static int current_sym_code;
|
|||
|
static int current_sym_value;
|
|||
|
static rtx current_sym_addr;
|
|||
|
|
|||
|
/* Number of chars of symbol-description generated so far for the
|
|||
|
current symbol. Used by CHARS and CONTIN. */
|
|||
|
|
|||
|
static int current_sym_nchars;
|
|||
|
|
|||
|
/* Report having output N chars of the current symbol-description. */
|
|||
|
|
|||
|
#define CHARS(N) (current_sym_nchars += (N))
|
|||
|
|
|||
|
/* Break the current symbol-description, generating a continuation,
|
|||
|
if it has become long. */
|
|||
|
|
|||
|
#ifndef DBX_CONTIN_LENGTH
|
|||
|
#define DBX_CONTIN_LENGTH 80
|
|||
|
#endif
|
|||
|
|
|||
|
#if DBX_CONTIN_LENGTH > 0
|
|||
|
#define CONTIN \
|
|||
|
do {if (current_sym_nchars > DBX_CONTIN_LENGTH) dbxout_continue ();} while (0)
|
|||
|
#else
|
|||
|
#define CONTIN
|
|||
|
#endif
|
|||
|
|
|||
|
void dbxout_types ();
|
|||
|
void dbxout_tags ();
|
|||
|
void dbxout_args ();
|
|||
|
void dbxout_symbol ();
|
|||
|
static void dbxout_type_name ();
|
|||
|
static void dbxout_type ();
|
|||
|
static void dbxout_finish_symbol ();
|
|||
|
static void dbxout_continue ();
|
|||
|
|
|||
|
/* At the beginning of compilation, start writing the symbol table.
|
|||
|
Initialize `typevec' and output the standard data types of C. */
|
|||
|
|
|||
|
void
|
|||
|
dbxout_init (asm_file, input_file_name)
|
|||
|
FILE *asm_file;
|
|||
|
char *input_file_name;
|
|||
|
{
|
|||
|
asmfile = asm_file;
|
|||
|
|
|||
|
typevec_len = 100;
|
|||
|
typevec = (enum typestatus *) xmalloc (typevec_len * sizeof typevec[0]);
|
|||
|
bzero (typevec, typevec_len * sizeof typevec[0]);
|
|||
|
|
|||
|
/* Used to put `Ltext:' before the reference, but that loses on sun 4. */
|
|||
|
fprintf (asmfile,
|
|||
|
"\t.stabs \"%s\",%d,0,0,Ltext\nLtext:\n",
|
|||
|
input_file_name, N_SO);
|
|||
|
|
|||
|
next_type_number = 1;
|
|||
|
next_block_number = 2;
|
|||
|
|
|||
|
/* Make sure that types `int' and `char' have numbers 1 and 2.
|
|||
|
Definitions of other integer types will refer to those numbers. */
|
|||
|
|
|||
|
dbxout_symbol (TYPE_NAME (integer_type_node), 0);
|
|||
|
dbxout_symbol (TYPE_NAME (char_type_node), 0);
|
|||
|
|
|||
|
/* Get all permanent types not yet gotten, and output them. */
|
|||
|
|
|||
|
dbxout_types (get_permanent_types ());
|
|||
|
}
|
|||
|
|
|||
|
/* Change by Bryan Boreham, Kewill, Sun Aug 13 15:31:25 1989.
|
|||
|
Added to support unexecing of compiler. */
|
|||
|
|
|||
|
void
|
|||
|
re_init_dbxout_for_unexec (asm_file, input_file_name)
|
|||
|
FILE *asm_file;
|
|||
|
char *input_file_name;
|
|||
|
{
|
|||
|
asmfile = asm_file;
|
|||
|
}
|
|||
|
|
|||
|
/* 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
|
|||
|
.stabs "start......\\",code,0,value
|
|||
|
.stabs "...rest",code,0,value */
|
|||
|
|
|||
|
static void
|
|||
|
dbxout_continue ()
|
|||
|
{
|
|||
|
#ifdef DBX_CONTIN_CHAR
|
|||
|
fprintf (asmfile, "%c", DBX_CONTIN_CHAR);
|
|||
|
#else
|
|||
|
fprintf (asmfile, "\\\\");
|
|||
|
#endif
|
|||
|
dbxout_finish_symbol ();
|
|||
|
fprintf (asmfile, ".stabs \"");
|
|||
|
current_sym_nchars = 0;
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
dbxout_type_fields (type)
|
|||
|
tree type;
|
|||
|
{
|
|||
|
tree tem;
|
|||
|
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_ANON_UNION_ELEM (tem))
|
|||
|
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)
|
|||
|
continue;
|
|||
|
/* Omit here the nameless fields that are used to skip bits. */
|
|||
|
else if (DECL_NAME (tem) != 0 && TREE_CODE (tem) != CONST_DECL)
|
|||
|
{
|
|||
|
/* Continue the line if necessary,
|
|||
|
but not before the first field. */
|
|||
|
if (tem != TYPE_FIELDS (type))
|
|||
|
CONTIN;
|
|||
|
|
|||
|
if (use_gdb_dbx_extensions
|
|||
|
&& flag_minimal_debug
|
|||
|
&& TREE_CODE (tem) == FIELD_DECL
|
|||
|
&& (DECL_VIRTUAL_P (tem) || DECL_VBASE_P (tem)))
|
|||
|
{
|
|||
|
CHARS (3 + TYPE_NAME_LENGTH (DECL_FCONTEXT (tem)));
|
|||
|
fprintf (asmfile, "$v%c",
|
|||
|
DECL_VIRTUAL_P (tem) ? 'f' : 'b');
|
|||
|
dbxout_type (DECL_FCONTEXT (tem), 0);
|
|||
|
fprintf (asmfile, ":");
|
|||
|
dbxout_type (TREE_TYPE (tem), 0);
|
|||
|
fprintf (asmfile, ",%d;", DECL_OFFSET (tem));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
fprintf (asmfile, "%s:", IDENTIFIER_POINTER (DECL_NAME (tem)));
|
|||
|
CHARS (2 + IDENTIFIER_LENGTH (DECL_NAME (tem)));
|
|||
|
|
|||
|
if (use_gdb_dbx_extensions)
|
|||
|
{
|
|||
|
putc ('/', asmfile);
|
|||
|
#ifdef TREE_PRIVATE
|
|||
|
putc ((TREE_PRIVATE (tem) ? '0'
|
|||
|
: TREE_PROTECTED (tem) ? '1' : '2'),
|
|||
|
asmfile);
|
|||
|
#endif
|
|||
|
CHARS (2);
|
|||
|
}
|
|||
|
|
|||
|
dbxout_type (TREE_TYPE (tem), 0);
|
|||
|
if (TREE_CODE (tem) == VAR_DECL && TREE_STATIC (tem))
|
|||
|
{
|
|||
|
if (use_gdb_dbx_extensions)
|
|||
|
{
|
|||
|
char *name = DECL_ASSEMBLER_NAME (tem);
|
|||
|
|
|||
|
/* Adding 1 here only works on systems
|
|||
|
which flush an initial underscore from
|
|||
|
the .stabs entry. This loses for static names
|
|||
|
which have an initial leading '_' on systems which
|
|||
|
don't use leading underscores. */
|
|||
|
if (name[0] == '_')
|
|||
|
name += 1;
|
|||
|
|
|||
|
fprintf (asmfile, ":%s;", name);
|
|||
|
CHARS (strlen (name));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fprintf (asmfile, ",0,0;");
|
|||
|
}
|
|||
|
}
|
|||
|
#if 0
|
|||
|
else if (TREE_CODE (tem) == VAR_DECL || TREE_CODE (tem) == CONST_DECL)
|
|||
|
{
|
|||
|
/* GDB 3.2 can't understand these declarations yet. */
|
|||
|
continue;
|
|||
|
}
|
|||
|
#endif
|
|||
|
else
|
|||
|
{
|
|||
|
fprintf (asmfile, ",%d,%d;", DECL_OFFSET (tem),
|
|||
|
TREE_INT_CST_LOW (DECL_SIZE (tem)) * DECL_SIZE_UNIT (tem));
|
|||
|
}
|
|||
|
CHARS (23);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Output a reference to a type. If the type has not yet been
|
|||
|
described in the dbx output, output its definition now.
|
|||
|
For a type already defined, just refer to its definition
|
|||
|
using the type number.
|
|||
|
|
|||
|
If FULL is nonzero, and the type has been described only with
|
|||
|
a forward-reference, output the definition now.
|
|||
|
If FULL is zero in this case, just refer to the forward-reference
|
|||
|
using the number previously allocated. */
|
|||
|
|
|||
|
static void
|
|||
|
dbxout_type (type, full)
|
|||
|
tree type;
|
|||
|
int full;
|
|||
|
{
|
|||
|
register tree fields, tem, method_vec;
|
|||
|
tree *methods, *end;
|
|||
|
char *vfield_name = 0;
|
|||
|
tree virtual_basetype = 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
|
|||
|
by assuming `int'. */
|
|||
|
if (type == error_mark_node)
|
|||
|
type = integer_type_node;
|
|||
|
else /* if (TYPE_SIZE (type) == 0) */
|
|||
|
type = TYPE_MAIN_VARIANT (type);
|
|||
|
|
|||
|
if (TYPE_SYMTAB_ADDRESS (type) == 0)
|
|||
|
{
|
|||
|
/* Type has no dbx number assigned. Assign next available number. */
|
|||
|
TYPE_SYMTAB_ADDRESS (type) = next_type_number++;
|
|||
|
|
|||
|
/* Make sure type vector is long enough to record about this type. */
|
|||
|
|
|||
|
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_len *= 2;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Output the number of this type, to refer to it. */
|
|||
|
fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type));
|
|||
|
CHARS (3);
|
|||
|
|
|||
|
/* If this type's definition has been output or is now being output,
|
|||
|
that is all. */
|
|||
|
|
|||
|
switch (typevec[TYPE_SYMTAB_ADDRESS (type)])
|
|||
|
{
|
|||
|
case TYPE_UNSEEN:
|
|||
|
break;
|
|||
|
case TYPE_XREF:
|
|||
|
if (! full)
|
|||
|
return;
|
|||
|
break;
|
|||
|
case TYPE_DEFINED:
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
#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)
|
|||
|
{
|
|||
|
typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF;
|
|||
|
return;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
/* Output a definition now. */
|
|||
|
|
|||
|
fprintf (asmfile, "=");
|
|||
|
CHARS (1);
|
|||
|
|
|||
|
/* 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;
|
|||
|
|
|||
|
switch (TREE_CODE (type))
|
|||
|
{
|
|||
|
case VOID_TYPE:
|
|||
|
case LANG_TYPE:
|
|||
|
/* For a void type, just define it as itself; ie, "5=5".
|
|||
|
This makes us consider it defined
|
|||
|
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);
|
|||
|
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. */
|
|||
|
fprintf (asmfile, "r2;0;127;");
|
|||
|
else
|
|||
|
/* Output other integer types as subranges of `int'. */
|
|||
|
fprintf (asmfile, "r1;%d;%d;",
|
|||
|
TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)),
|
|||
|
TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)));
|
|||
|
CHARS (25);
|
|||
|
break;
|
|||
|
|
|||
|
case REAL_TYPE:
|
|||
|
/* This must be magic. */
|
|||
|
fprintf (asmfile, "r1;%d;0;",
|
|||
|
TREE_INT_CST_LOW (size_in_bytes (type)));
|
|||
|
CHARS (16);
|
|||
|
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. */
|
|||
|
fprintf (asmfile, "ar1;0;%d;",
|
|||
|
(TYPE_DOMAIN (type)
|
|||
|
? TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
|
|||
|
: -1));
|
|||
|
CHARS (17);
|
|||
|
dbxout_type (TREE_TYPE (type), 0);
|
|||
|
break;
|
|||
|
|
|||
|
case RECORD_TYPE:
|
|||
|
case UNION_TYPE:
|
|||
|
{
|
|||
|
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (type);
|
|||
|
|
|||
|
/* Output a structure type. */
|
|||
|
if ((TYPE_NAME (type) != 0 && !full)
|
|||
|
|| TYPE_SIZE (type) == 0)
|
|||
|
{
|
|||
|
/* If the type is just a cross reference, output one
|
|||
|
and mark the type as partially described.
|
|||
|
If it later becomes defined, we will output
|
|||
|
its real definition.
|
|||
|
If the type has a name, don't nest its name within
|
|||
|
another type's definition; instead, output an xref
|
|||
|
and let the definition come when the name is defined. */
|
|||
|
fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "xs" : "xu");
|
|||
|
CHARS (3);
|
|||
|
dbxout_type_name (type);
|
|||
|
fprintf (asmfile, ":");
|
|||
|
typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF;
|
|||
|
break;
|
|||
|
}
|
|||
|
tem = size_in_bytes (type);
|
|||
|
fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "s%d" : "u%d",
|
|||
|
TREE_INT_CST_LOW (tem));
|
|||
|
|
|||
|
if (use_gdb_dbx_extensions)
|
|||
|
{
|
|||
|
if (n_baseclasses)
|
|||
|
{
|
|||
|
fprintf (asmfile, "!%d,", n_baseclasses);
|
|||
|
CHARS (8);
|
|||
|
}
|
|||
|
}
|
|||
|
for (i = 1; i <= n_baseclasses; i++)
|
|||
|
{
|
|||
|
tree basetype = CLASSTYPE_BASECLASS (type, i);
|
|||
|
if (use_gdb_dbx_extensions)
|
|||
|
{
|
|||
|
putc (CLASSTYPE_VIA_VIRTUAL (type, i) ? '1'
|
|||
|
: '0',
|
|||
|
asmfile);
|
|||
|
putc (CLASSTYPE_VIA_PUBLIC (type, i) ? '2'
|
|||
|
: '0',
|
|||
|
asmfile);
|
|||
|
fprintf (asmfile, "%d,", DECL_OFFSET (TYPE_NAME (basetype)));
|
|||
|
CHARS (15);
|
|||
|
dbxout_type (basetype, 0);
|
|||
|
putc (';', asmfile);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Print out the base class information with fields
|
|||
|
which have the same names at the types they hold. */
|
|||
|
dbxout_type_name (basetype);
|
|||
|
putc (':', asmfile);
|
|||
|
dbxout_type (basetype, full);
|
|||
|
fprintf (asmfile, ",%d,%d;",
|
|||
|
DECL_OFFSET (TYPE_NAME (basetype)),
|
|||
|
TREE_INT_CST_LOW (TYPE_SIZE (basetype)) * DECL_SIZE_UNIT (basetype));
|
|||
|
CHARS (20);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CHARS (11);
|
|||
|
|
|||
|
/* Write out the field declarations. */
|
|||
|
dbxout_type_fields (type);
|
|||
|
|
|||
|
/* C++: put out the method names and their parameter lists */
|
|||
|
/* We do constructors, destructor, if any, followed by the method names. */
|
|||
|
method_vec = use_gdb_dbx_extensions ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
|
|||
|
methods = 0;
|
|||
|
end = 0;
|
|||
|
if (use_gdb_dbx_extensions
|
|||
|
&& TREE_CODE (type) == RECORD_TYPE
|
|||
|
&& (TYPE_HAS_DESTRUCTOR (type) | TYPE_HAS_CONSTRUCTOR (type)))
|
|||
|
{
|
|||
|
tree dtor;
|
|||
|
|
|||
|
methods = &TREE_VEC_ELT (method_vec, 0);
|
|||
|
end = TREE_VEC_END (method_vec);
|
|||
|
/* Destructors lie in a special place. */
|
|||
|
if (TYPE_HAS_DESTRUCTOR (type))
|
|||
|
{
|
|||
|
dtor = TREE_VEC_ELT (method_vec, 0);
|
|||
|
tem = TREE_CHAIN (dtor);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
dtor = NULL_TREE;
|
|||
|
tem = *methods;
|
|||
|
}
|
|||
|
|
|||
|
CHARS (2);
|
|||
|
|
|||
|
if (tem)
|
|||
|
{
|
|||
|
if (TREE_OPERATOR (tem))
|
|||
|
/* Operators do not belong here. This is for
|
|||
|
constructors and destructors only. */
|
|||
|
abort ();
|
|||
|
else
|
|||
|
{
|
|||
|
fprintf (asmfile, "%s::", IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (tem)));
|
|||
|
CHARS (IDENTIFIER_LENGTH (DECL_ORIGINAL_NAME (tem)) + 3);
|
|||
|
}
|
|||
|
|
|||
|
while (tem)
|
|||
|
{
|
|||
|
/* Output the name of the field (after overloading), as
|
|||
|
well as the name of the field before overloading, along
|
|||
|
with its parameter list. */
|
|||
|
char c;
|
|||
|
char *debug_name = IDENTIFIER_POINTER (DECL_NAME (tem));
|
|||
|
int old_minimal_debug = flag_minimal_debug;
|
|||
|
|
|||
|
CONTIN;
|
|||
|
|
|||
|
if (tem == dtor)
|
|||
|
/* Always output destructors with full information. */
|
|||
|
flag_minimal_debug = 0;
|
|||
|
|
|||
|
dbxout_type (TREE_TYPE (tem), 0);
|
|||
|
flag_minimal_debug = old_minimal_debug;
|
|||
|
|
|||
|
if (DECL_VIRTUAL_P (tem))
|
|||
|
c = '*';
|
|||
|
else if (DECL_STATIC_FUNCTION_P (tem))
|
|||
|
c = '?';
|
|||
|
else
|
|||
|
c = '.';
|
|||
|
|
|||
|
if (flag_minimal_debug && tem != dtor)
|
|||
|
{
|
|||
|
/* Cut down on debugging information by not outputting
|
|||
|
the parts of the name we can just as easily
|
|||
|
have the debugger figure out. */
|
|||
|
|
|||
|
/* Get past '__'. */
|
|||
|
debug_name += 2;
|
|||
|
/* Get past const and volatile qualifiers. */
|
|||
|
while (*debug_name == 'C' || *debug_name == 'V')
|
|||
|
debug_name++;
|
|||
|
/* Get past numeric type length prefix. */
|
|||
|
while (*debug_name >= '0' && *debug_name <= '9')
|
|||
|
debug_name++;
|
|||
|
/* Get past type of `this'. */
|
|||
|
debug_name += IDENTIFIER_LENGTH (DECL_NAME (TYPE_NAME (type)));
|
|||
|
}
|
|||
|
fprintf (asmfile, ":%s;%c%c", debug_name,
|
|||
|
TREE_PRIVATE (tem) ? '0' : TREE_PROTECTED (tem) ? '1' : '2', c);
|
|||
|
CHARS (IDENTIFIER_LENGTH (DECL_NAME (tem)) + 5
|
|||
|
- (debug_name - IDENTIFIER_POINTER (DECL_NAME (tem))));
|
|||
|
if (DECL_VIRTUAL_P (tem))
|
|||
|
{
|
|||
|
fprintf (asmfile, "%d;",
|
|||
|
TREE_INT_CST_LOW (DECL_VINDEX (tem)));
|
|||
|
CHARS (8);
|
|||
|
}
|
|||
|
if (tem == dtor)
|
|||
|
break;
|
|||
|
tem = TREE_CHAIN (tem);
|
|||
|
if (tem == NULL_TREE)
|
|||
|
tem = dtor;
|
|||
|
}
|
|||
|
putc (';', asmfile);
|
|||
|
}
|
|||
|
if (methods != end)
|
|||
|
methods++;
|
|||
|
}
|
|||
|
else if (method_vec != NULL_TREE)
|
|||
|
{
|
|||
|
methods = &TREE_VEC_ELT (method_vec, 1);
|
|||
|
end = TREE_VEC_END (method_vec);
|
|||
|
}
|
|||
|
|
|||
|
for (; methods != end; methods++)
|
|||
|
{
|
|||
|
tem = *methods;
|
|||
|
|
|||
|
if (tem)
|
|||
|
{
|
|||
|
if (TREE_OPERATOR (tem))
|
|||
|
{
|
|||
|
char *name1 = operator_name_string (DECL_NAME (tem));
|
|||
|
fprintf (asmfile, "op$::%s.", name1);
|
|||
|
CHARS (strlen (name1) + 6);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
tree name = DECL_ORIGINAL_NAME (tem);
|
|||
|
fprintf (asmfile, "%s::", IDENTIFIER_POINTER (name));
|
|||
|
CHARS (IDENTIFIER_LENGTH (name) + 3);
|
|||
|
}
|
|||
|
|
|||
|
for (; tem; tem = TREE_CHAIN (tem))
|
|||
|
/* Output the name of the field (after overloading), as
|
|||
|
well as the name of the field before overloading, along
|
|||
|
with its parameter list */
|
|||
|
{
|
|||
|
/* @@ */
|
|||
|
char c;
|
|||
|
char *debug_name = IDENTIFIER_POINTER (DECL_NAME (tem));
|
|||
|
|
|||
|
CONTIN;
|
|||
|
|
|||
|
dbxout_type (TREE_TYPE (tem), 0);
|
|||
|
if (DECL_VIRTUAL_P (tem))
|
|||
|
c = '*';
|
|||
|
else if (DECL_STATIC_FUNCTION_P (tem))
|
|||
|
c = '?';
|
|||
|
else
|
|||
|
c = '.';
|
|||
|
|
|||
|
if (flag_minimal_debug)
|
|||
|
{
|
|||
|
debug_name += IDENTIFIER_LENGTH (DECL_ORIGINAL_NAME (tem)) + 2;
|
|||
|
while (*debug_name == 'C' || *debug_name == 'V')
|
|||
|
debug_name++;
|
|||
|
while (*debug_name >= '0' && *debug_name <= '9')
|
|||
|
debug_name++;
|
|||
|
debug_name += IDENTIFIER_LENGTH (DECL_NAME (TYPE_NAME (type)));
|
|||
|
}
|
|||
|
|
|||
|
fprintf (asmfile, ":%s;%c%c", debug_name,
|
|||
|
TREE_PRIVATE (tem) ? '0' : TREE_PROTECTED (tem) ? '1' : '2', c);
|
|||
|
CHARS (IDENTIFIER_LENGTH (DECL_NAME (tem)) + 6
|
|||
|
- (debug_name - IDENTIFIER_POINTER (DECL_NAME (tem))));
|
|||
|
if (DECL_VIRTUAL_P (tem))
|
|||
|
{
|
|||
|
fprintf (asmfile, "%d;",
|
|||
|
TREE_INT_CST_LOW (DECL_VINDEX (tem)));
|
|||
|
CHARS (8);
|
|||
|
}
|
|||
|
}
|
|||
|
putc (';', asmfile);
|
|||
|
CHARS (1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
putc (';', asmfile);
|
|||
|
|
|||
|
if (use_gdb_dbx_extensions && TREE_CODE (type) == RECORD_TYPE)
|
|||
|
{
|
|||
|
/* Tell GDB+ that it may keep reading. */
|
|||
|
putc ('~', asmfile);
|
|||
|
if (TYPE_HAS_DESTRUCTOR (type) && TYPE_HAS_CONSTRUCTOR (type))
|
|||
|
putc ('=', asmfile);
|
|||
|
else if (TYPE_HAS_DESTRUCTOR (type))
|
|||
|
putc ('-', asmfile);
|
|||
|
else if (TYPE_HAS_CONSTRUCTOR (type))
|
|||
|
putc ('+', asmfile);
|
|||
|
|
|||
|
if (CLASSTYPE_VSIZE (type))
|
|||
|
{
|
|||
|
putc ('%', asmfile);
|
|||
|
dbxout_type (DECL_FCONTEXT (CLASSTYPE_VFIELD (type)), 0);
|
|||
|
fprintf (asmfile, ";");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
putc (';', asmfile);
|
|||
|
CHARS (3);
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case ENUMERAL_TYPE:
|
|||
|
if ((TYPE_NAME (type) != 0
|
|||
|
&& !full
|
|||
|
&& ((TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
|
|||
|
&& ! ANON_AGGRNAME_P (DECL_NAME (TYPE_NAME (type))))
|
|||
|
|| (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE
|
|||
|
&& ! ANON_AGGRNAME_P (TYPE_NAME (type)))))
|
|||
|
|| TYPE_SIZE (type) == 0)
|
|||
|
{
|
|||
|
fprintf (asmfile, "xe");
|
|||
|
CHARS (3);
|
|||
|
dbxout_type_name (type);
|
|||
|
typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF;
|
|||
|
fprintf (asmfile, ":");
|
|||
|
return;
|
|||
|
}
|
|||
|
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)));
|
|||
|
if (TREE_CHAIN (tem) != 0)
|
|||
|
CONTIN;
|
|||
|
}
|
|||
|
putc (';', asmfile);
|
|||
|
CHARS (1);
|
|||
|
break;
|
|||
|
|
|||
|
case POINTER_TYPE:
|
|||
|
putc ('*', asmfile);
|
|||
|
CHARS (1);
|
|||
|
dbxout_type (TREE_TYPE (type), 0);
|
|||
|
break;
|
|||
|
|
|||
|
case METHOD_TYPE:
|
|||
|
if (use_gdb_dbx_extensions)
|
|||
|
{
|
|||
|
putc ('#', asmfile);
|
|||
|
CHARS (1);
|
|||
|
if (flag_minimal_debug)
|
|||
|
{
|
|||
|
putc ('#', asmfile);
|
|||
|
dbxout_type (TREE_TYPE (type), 0);
|
|||
|
putc (';', asmfile);
|
|||
|
CHARS (1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
dbxout_type (TYPE_METHOD_BASETYPE (type), 0);
|
|||
|
putc (',', asmfile);
|
|||
|
CHARS (1);
|
|||
|
dbxout_type (TREE_TYPE (type), 0);
|
|||
|
dbxout_args (TYPE_ARG_TYPES (type));
|
|||
|
putc (';', asmfile);
|
|||
|
CHARS (1);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Should print as an int, because it is really
|
|||
|
just an offset. */
|
|||
|
dbxout_type (integer_type_node, 0);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case OFFSET_TYPE:
|
|||
|
if (use_gdb_dbx_extensions)
|
|||
|
{
|
|||
|
putc ('@', asmfile);
|
|||
|
CHARS (1);
|
|||
|
dbxout_type (TYPE_OFFSET_BASETYPE (type), 0);
|
|||
|
putc (',', asmfile);
|
|||
|
CHARS (1);
|
|||
|
dbxout_type (TREE_TYPE (type), 0);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* Should print as an int, because it is really
|
|||
|
just an offset. */
|
|||
|
dbxout_type (integer_type_node, 0);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case REFERENCE_TYPE:
|
|||
|
putc (use_gdb_dbx_extensions ? '&' : '*', asmfile);
|
|||
|
CHARS (1);
|
|||
|
dbxout_type (TREE_TYPE (type), 0);
|
|||
|
break;
|
|||
|
|
|||
|
case FUNCTION_TYPE:
|
|||
|
putc ('f', asmfile);
|
|||
|
CHARS (1);
|
|||
|
dbxout_type (TREE_TYPE (type), 0);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
abort ();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Output the name of type TYPE, with no punctuation.
|
|||
|
Such names can be set up either by typedef declarations
|
|||
|
or by struct, enum and union tags. */
|
|||
|
|
|||
|
static void
|
|||
|
dbxout_type_name (type)
|
|||
|
register tree type;
|
|||
|
{
|
|||
|
tree t;
|
|||
|
if (TYPE_NAME (type) == 0)
|
|||
|
abort ();
|
|||
|
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
|
|||
|
{
|
|||
|
t = TYPE_NAME (type);
|
|||
|
}
|
|||
|
else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL)
|
|||
|
{
|
|||
|
t = DECL_NAME (TYPE_NAME (type));
|
|||
|
}
|
|||
|
else
|
|||
|
abort ();
|
|||
|
|
|||
|
fprintf (asmfile, "%s", IDENTIFIER_POINTER (t));
|
|||
|
CHARS (IDENTIFIER_LENGTH (t));
|
|||
|
}
|
|||
|
|
|||
|
/* Output a .stabs for the symbol defined by DECL,
|
|||
|
which must be a ..._DECL node in the normal namespace.
|
|||
|
It may be a CONST_DECL, a FUNCTION_DECL, a PARM_DECL or a VAR_DECL.
|
|||
|
LOCAL is nonzero if the scope is less than the entire file. */
|
|||
|
|
|||
|
void
|
|||
|
dbxout_symbol (decl, local)
|
|||
|
tree decl;
|
|||
|
int local;
|
|||
|
{
|
|||
|
int letter = 0;
|
|||
|
tree type = TREE_TYPE (decl);
|
|||
|
char *name;
|
|||
|
int regno = -1;
|
|||
|
|
|||
|
/* If global, first output all types and all
|
|||
|
struct, enum and union tags that have been created
|
|||
|
and not yet output. */
|
|||
|
|
|||
|
if (local == 0)
|
|||
|
{
|
|||
|
/* Send out the tags first. */
|
|||
|
dbxout_tags (gettags ());
|
|||
|
dbxout_types (get_permanent_types ());
|
|||
|
}
|
|||
|
|
|||
|
current_sym_code = 0;
|
|||
|
current_sym_value = 0;
|
|||
|
current_sym_addr = 0;
|
|||
|
|
|||
|
/* The output will always start with the symbol name,
|
|||
|
so count that always in the length-output-so-far. */
|
|||
|
|
|||
|
if (DECL_NAME (decl) == 0)
|
|||
|
return;
|
|||
|
|
|||
|
current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (decl));
|
|||
|
|
|||
|
switch (TREE_CODE (decl))
|
|||
|
{
|
|||
|
case CONST_DECL:
|
|||
|
/* Enum values are defined by defining the enum type. */
|
|||
|
break;
|
|||
|
|
|||
|
case FUNCTION_DECL:
|
|||
|
if (DECL_RTL (decl) == 0)
|
|||
|
return;
|
|||
|
if (TREE_EXTERNAL (decl))
|
|||
|
break;
|
|||
|
if (GET_CODE (DECL_RTL (decl)) != MEM
|
|||
|
|| GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
|
|||
|
break;
|
|||
|
FORCE_TEXT;
|
|||
|
fprintf (asmfile, ".stabs \"%s:%c",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (decl)),
|
|||
|
TREE_PUBLIC (decl) ? 'F' : 'f');
|
|||
|
|
|||
|
current_sym_code = N_FUN;
|
|||
|
current_sym_addr = XEXP (DECL_RTL (decl), 0);
|
|||
|
|
|||
|
if (TREE_TYPE (TREE_TYPE (decl)))
|
|||
|
dbxout_type (TREE_TYPE (TREE_TYPE (decl)), 0);
|
|||
|
else
|
|||
|
dbxout_type (void_type_node, 0);
|
|||
|
dbxout_finish_symbol ();
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_DECL:
|
|||
|
#if 0
|
|||
|
/* This seems all wrong. Outputting most kinds of types gives no name
|
|||
|
at all. A true definition gives no name; a cross-ref for a
|
|||
|
structure can give the tag name, but not a type name.
|
|||
|
It seems that no typedef name is defined by outputting a type. */
|
|||
|
|
|||
|
/* If this typedef name was defined by outputting the type,
|
|||
|
don't duplicate it. */
|
|||
|
if (typevec[TYPE_SYMTAB_ADDRESS (type)] == 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)
|
|||
|
|| lang_output_debug_info (TREE_TYPE (decl)) == 0)
|
|||
|
return;
|
|||
|
|
|||
|
/* Output typedef name. */
|
|||
|
FORCE_TEXT;
|
|||
|
fprintf (asmfile, ".stabs \"%s:t",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (decl)));
|
|||
|
|
|||
|
current_sym_code = N_LSYM;
|
|||
|
|
|||
|
dbxout_type (TREE_TYPE (decl), 1);
|
|||
|
dbxout_finish_symbol ();
|
|||
|
|
|||
|
/* Prevent duplicate output of a typedef. */
|
|||
|
TREE_ASM_WRITTEN (decl) = 1;
|
|||
|
break;
|
|||
|
|
|||
|
case PARM_DECL:
|
|||
|
/* Parm decls go in their own separate chains
|
|||
|
and are output by dbxout_reg_parms and dbxout_parms. */
|
|||
|
abort ();
|
|||
|
|
|||
|
case RESULT_DECL:
|
|||
|
/* Named return value, treat like a VAR_DECL. */
|
|||
|
case VAR_DECL:
|
|||
|
if (DECL_RTL (decl) == 0)
|
|||
|
return;
|
|||
|
/* Don't mention a variable that is external.
|
|||
|
Let the file that defines it describe it. */
|
|||
|
if (TREE_EXTERNAL (decl))
|
|||
|
break;
|
|||
|
|
|||
|
/* If the variable is really a constant, inform dbx of such. */
|
|||
|
if (TREE_STATIC (decl) && TREE_READONLY (decl)
|
|||
|
&& DECL_INITIAL (decl) != 0
|
|||
|
&& (DECL_FIELD_CONTEXT (decl) == NULL_TREE
|
|||
|
|| TREE_CODE (DECL_FIELD_CONTEXT (decl)) == LET_STMT))
|
|||
|
{
|
|||
|
if (TREE_PUBLIC (decl) == 0)
|
|||
|
{
|
|||
|
/* The sun4 assembler does not grok this. */
|
|||
|
name = IDENTIFIER_POINTER (DECL_NAME (decl));
|
|||
|
if (TREE_CODE (TREE_TYPE (decl)) == INTEGER_TYPE
|
|||
|
|| TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE)
|
|||
|
{
|
|||
|
int ival = TREE_INT_CST_LOW (DECL_INITIAL (decl));
|
|||
|
fprintf (asmfile, ".stabs \"%s:c=i%d\",0x%x,0,0,0\n",
|
|||
|
name, ival, N_LSYM);
|
|||
|
return;
|
|||
|
}
|
|||
|
else if (TREE_CODE (TREE_TYPE (decl)) == REAL_TYPE)
|
|||
|
{
|
|||
|
/* don't know how to do this yet. */
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
/* else it is something we handle like a normal variable. */
|
|||
|
}
|
|||
|
|
|||
|
/* Don't mention a variable at all
|
|||
|
if it was completely optimized into nothingness.
|
|||
|
|
|||
|
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)
|
|||
|
{
|
|||
|
regno = REGNO (DECL_RTL (decl));
|
|||
|
if (regno >= FIRST_PSEUDO_REGISTER)
|
|||
|
regno = reg_renumber[REGNO (DECL_RTL (decl))];
|
|||
|
if (regno < 0)
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
/* 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)
|
|||
|
{
|
|||
|
if (TREE_PUBLIC (decl))
|
|||
|
{
|
|||
|
letter = 'G';
|
|||
|
current_sym_code = N_GSYM;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
current_sym_addr = XEXP (DECL_RTL (decl), 0);
|
|||
|
|
|||
|
letter = TREE_PERMANENT (decl) ? 'S' : 'V';
|
|||
|
|
|||
|
if (!DECL_INITIAL (decl))
|
|||
|
current_sym_code = N_LCSYM;
|
|||
|
else if (TREE_READONLY (decl) && ! TREE_VOLATILE (decl))
|
|||
|
/* This is not quite right, but it's the closest
|
|||
|
of all the codes that Unix defines. */
|
|||
|
current_sym_code = N_FUN;
|
|||
|
else
|
|||
|
current_sym_code = N_STSYM;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (regno >= 0)
|
|||
|
{
|
|||
|
letter = 'r';
|
|||
|
current_sym_code = N_RSYM;
|
|||
|
current_sym_value = DBX_REGISTER_NUMBER (regno);
|
|||
|
}
|
|||
|
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 = INTVAL (XEXP (XEXP (XEXP (DECL_RTL (decl), 0), 0), 1));
|
|||
|
}
|
|||
|
|
|||
|
/* 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. */
|
|||
|
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 = 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)
|
|||
|
{
|
|||
|
current_sym_code = N_LSYM;
|
|||
|
/* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...)))
|
|||
|
We want the value of that CONST_INT. */
|
|||
|
current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (decl), 0), 1));
|
|||
|
}
|
|||
|
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;
|
|||
|
|
|||
|
/* Ok, start a symtab entry and output the variable name. */
|
|||
|
FORCE_TEXT;
|
|||
|
/* 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. */
|
|||
|
if (DECL_LANG_SPECIFIC (decl))
|
|||
|
{
|
|||
|
name = DECL_ASSEMBLER_NAME (decl);
|
|||
|
|
|||
|
/* Adding 1 here only works on systems
|
|||
|
which flush an initial underscore. */
|
|||
|
if (name[0] == '_')
|
|||
|
name += 1;
|
|||
|
}
|
|||
|
else name = IDENTIFIER_POINTER (DECL_NAME (decl));
|
|||
|
|
|||
|
fprintf (asmfile, ".stabs \"%s:", name);
|
|||
|
if (letter) putc (letter, asmfile);
|
|||
|
dbxout_type (type, 0);
|
|||
|
dbxout_finish_symbol ();
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
dbxout_finish_symbol ()
|
|||
|
{
|
|||
|
fprintf (asmfile, "\",%d,0,0,", current_sym_code);
|
|||
|
if (current_sym_addr)
|
|||
|
output_addr_const (asmfile, current_sym_addr);
|
|||
|
else
|
|||
|
fprintf (asmfile, "%d", current_sym_value);
|
|||
|
putc ('\n', asmfile);
|
|||
|
}
|
|||
|
|
|||
|
/* Output definitions of all the decls in a chain. */
|
|||
|
|
|||
|
static void
|
|||
|
dbxout_syms (syms)
|
|||
|
tree syms;
|
|||
|
{
|
|||
|
while (syms)
|
|||
|
{
|
|||
|
dbxout_symbol (syms, 1);
|
|||
|
syms = TREE_CHAIN (syms);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* The following two functions output definitions of function parameters.
|
|||
|
Each parameter gets a definition locating it in the parameter list.
|
|||
|
Each parameter that is a register variable gets a second definition
|
|||
|
locating it in the register.
|
|||
|
|
|||
|
Printing or argument lists in gdb uses the definitions that
|
|||
|
locate in the parameter list. But reference to the variable in
|
|||
|
expressions uses preferentially the definition as a register. */
|
|||
|
|
|||
|
/* Output definitions, referring to storage in the parmlist,
|
|||
|
of all the parms in PARMS, which is a chain of PARM_DECL nodes. */
|
|||
|
|
|||
|
static void
|
|||
|
dbxout_parms (parms)
|
|||
|
tree parms;
|
|||
|
{
|
|||
|
for (; parms; parms = TREE_CHAIN (parms))
|
|||
|
{
|
|||
|
int regno = -1;
|
|||
|
|
|||
|
if (GET_CODE (DECL_RTL (parms)) == REG)
|
|||
|
regno = REGNO (DECL_RTL (parms));
|
|||
|
if (regno >= FIRST_PSEUDO_REGISTER)
|
|||
|
regno = reg_renumber[regno];
|
|||
|
|
|||
|
if (DECL_OFFSET (parms) >= 0)
|
|||
|
{
|
|||
|
current_sym_code = N_PSYM;
|
|||
|
current_sym_value = DECL_OFFSET (parms) / BITS_PER_UNIT;
|
|||
|
current_sym_addr = 0;
|
|||
|
|
|||
|
FORCE_TEXT;
|
|||
|
if (DECL_NAME (parms))
|
|||
|
{
|
|||
|
current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms));
|
|||
|
|
|||
|
fprintf (asmfile, ".stabs \"%s:p",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (parms)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
current_sym_nchars = 8;
|
|||
|
fprintf (asmfile, ".stabs \"(anon):p");
|
|||
|
}
|
|||
|
|
|||
|
if (regno >= 0)
|
|||
|
dbxout_type (DECL_ARG_TYPE (parms), 0);
|
|||
|
else
|
|||
|
{
|
|||
|
/* 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. */
|
|||
|
#ifdef 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);
|
|||
|
else
|
|||
|
{
|
|||
|
current_sym_value = DECL_OFFSET (parms) / BITS_PER_UNIT;
|
|||
|
dbxout_type (DECL_ARG_TYPE (parms), 0);
|
|||
|
}
|
|||
|
}
|
|||
|
dbxout_finish_symbol ();
|
|||
|
}
|
|||
|
/* Parm was passed in registers.
|
|||
|
If it lives in a hard register, output a "regparm" symbol
|
|||
|
for the register it lives in. */
|
|||
|
else if (regno >= 0)
|
|||
|
{
|
|||
|
current_sym_code = N_RSYM;
|
|||
|
current_sym_value = DBX_REGISTER_NUMBER (regno);
|
|||
|
current_sym_addr = 0;
|
|||
|
|
|||
|
FORCE_TEXT;
|
|||
|
if (DECL_NAME (parms))
|
|||
|
{
|
|||
|
current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms));
|
|||
|
fprintf (asmfile, ".stabs \"%s:P",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (parms)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
current_sym_nchars = 8;
|
|||
|
fprintf (asmfile, ".stabs \"(anon):P");
|
|||
|
}
|
|||
|
|
|||
|
dbxout_type (DECL_ARG_TYPE (parms), 0);
|
|||
|
dbxout_finish_symbol ();
|
|||
|
}
|
|||
|
else if (GET_CODE (DECL_RTL (parms)) == MEM
|
|||
|
&& XEXP (DECL_RTL (parms), 0) != const0_rtx)
|
|||
|
{
|
|||
|
current_sym_code = N_LSYM;
|
|||
|
/* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))).
|
|||
|
We want the value of that CONST_INT. */
|
|||
|
current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1));
|
|||
|
current_sym_addr = 0;
|
|||
|
|
|||
|
FORCE_TEXT;
|
|||
|
if (DECL_NAME (parms))
|
|||
|
{
|
|||
|
current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms));
|
|||
|
fprintf (asmfile, ".stabs \"%s:p",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (parms)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
current_sym_nchars = 8;
|
|||
|
fprintf (asmfile, ".stabs \"(anon):p");
|
|||
|
}
|
|||
|
|
|||
|
#if 0 /* This is actually the case in which a parameter
|
|||
|
is passed in registers but lives on the stack in a local slot.
|
|||
|
The address we are using is already correct, so don't change it. */
|
|||
|
|
|||
|
/* 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. */
|
|||
|
#ifdef 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
|
|||
|
#endif /* 0 */
|
|||
|
|
|||
|
dbxout_type (TREE_TYPE (parms), 0);
|
|||
|
dbxout_finish_symbol ();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Output definitions, referring to registers,
|
|||
|
of all the parms in PARMS which are stored in registers during the function.
|
|||
|
PARMS is a chain of PARM_DECL nodes. */
|
|||
|
|
|||
|
static void
|
|||
|
dbxout_reg_parms (parms)
|
|||
|
tree parms;
|
|||
|
{
|
|||
|
while (parms)
|
|||
|
{
|
|||
|
int regno = -1;
|
|||
|
|
|||
|
if (GET_CODE (DECL_RTL (parms)) == REG)
|
|||
|
regno = REGNO (DECL_RTL (parms));
|
|||
|
if (regno >= FIRST_PSEUDO_REGISTER)
|
|||
|
regno = reg_renumber[regno];
|
|||
|
|
|||
|
/* Report parms that live in registers during the function. */
|
|||
|
if (regno >= 0
|
|||
|
&& DECL_OFFSET (parms) >= 0)
|
|||
|
{
|
|||
|
current_sym_code = N_RSYM;
|
|||
|
current_sym_value = DBX_REGISTER_NUMBER (regno);
|
|||
|
current_sym_addr = 0;
|
|||
|
|
|||
|
FORCE_TEXT;
|
|||
|
if (DECL_NAME (parms))
|
|||
|
{
|
|||
|
current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms));
|
|||
|
fprintf (asmfile, ".stabs \"%s:r",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (parms)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
current_sym_nchars = 8;
|
|||
|
fprintf (asmfile, ".stabs \"(anon):r");
|
|||
|
}
|
|||
|
dbxout_type (TREE_TYPE (parms), 0);
|
|||
|
dbxout_finish_symbol ();
|
|||
|
}
|
|||
|
/* Report parms that live in memory but outside the parmlist. */
|
|||
|
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)
|
|||
|
{
|
|||
|
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. */
|
|||
|
#ifdef 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)
|
|||
|
{
|
|||
|
current_sym_code = N_LSYM;
|
|||
|
current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1));
|
|||
|
current_sym_addr = 0;
|
|||
|
FORCE_TEXT;
|
|||
|
if (DECL_NAME (parms))
|
|||
|
{
|
|||
|
current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms));
|
|||
|
fprintf (asmfile, ".stabs \"%s:",
|
|||
|
IDENTIFIER_POINTER (DECL_NAME (parms)));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
current_sym_nchars = 8;
|
|||
|
fprintf (asmfile, ".stabs \"(anon):");
|
|||
|
}
|
|||
|
dbxout_type (TREE_TYPE (parms), 0);
|
|||
|
dbxout_finish_symbol ();
|
|||
|
}
|
|||
|
}
|
|||
|
parms = TREE_CHAIN (parms);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Given a chain of ..._TYPE nodes (as come in a parameter list),
|
|||
|
output definitions of those names, in raw form */
|
|||
|
|
|||
|
void
|
|||
|
dbxout_args (args)
|
|||
|
tree args;
|
|||
|
{
|
|||
|
while (args)
|
|||
|
{
|
|||
|
putc (',', asmfile);
|
|||
|
dbxout_type (TREE_VALUE (args), 0);
|
|||
|
CHARS (1);
|
|||
|
args = TREE_CHAIN (args);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Given a chain of ..._TYPE nodes,
|
|||
|
find those which have typedef names and output those names.
|
|||
|
This is to ensure those types get output. */
|
|||
|
|
|||
|
void
|
|||
|
dbxout_types (types)
|
|||
|
register tree types;
|
|||
|
{
|
|||
|
while (types)
|
|||
|
{
|
|||
|
if (TYPE_NAME (types)
|
|||
|
&& TREE_CODE (TYPE_NAME (types)) == TYPE_DECL
|
|||
|
&& ! TREE_ASM_WRITTEN (TYPE_NAME (types)))
|
|||
|
dbxout_symbol (TYPE_NAME (types), 1);
|
|||
|
types = TREE_CHAIN (types);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Output the tags (struct, union and enum definitions with names) for a block,
|
|||
|
given a list of them (a chain of TREE_LIST nodes) in TAGS.
|
|||
|
We must check to include those that have been mentioned already with
|
|||
|
only a cross-reference. */
|
|||
|
|
|||
|
void
|
|||
|
dbxout_tags (tags)
|
|||
|
tree tags;
|
|||
|
{
|
|||
|
register tree link;
|
|||
|
for (link = tags; link; link = TREE_CHAIN (link))
|
|||
|
{
|
|||
|
register tree type = TYPE_MAIN_VARIANT (TREE_VALUE (link));
|
|||
|
if (TREE_PURPOSE (link) != 0
|
|||
|
&& ! TREE_ASM_WRITTEN (link)
|
|||
|
&& TYPE_SIZE (type) != 0
|
|||
|
&& lang_output_debug_info (type))
|
|||
|
{
|
|||
|
TREE_ASM_WRITTEN (link) = 1;
|
|||
|
current_sym_code = N_LSYM;
|
|||
|
current_sym_value = 0;
|
|||
|
current_sym_addr = 0;
|
|||
|
current_sym_nchars = 2 + IDENTIFIER_LENGTH (TREE_PURPOSE (link));
|
|||
|
|
|||
|
FORCE_TEXT;
|
|||
|
fprintf (asmfile, ".stabs \"%s:T",
|
|||
|
ANON_AGGRNAME_P (TREE_PURPOSE (link))
|
|||
|
? "" : IDENTIFIER_POINTER (TREE_PURPOSE (link)));
|
|||
|
|
|||
|
/* If there is a typedecl for this type with the same name
|
|||
|
as the tag, output an abbreviated form for that typedecl. */
|
|||
|
if (use_gdb_dbx_extensions
|
|||
|
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
|
|||
|
&& DECL_NAME (TYPE_NAME (type)) == TREE_PURPOSE (link))
|
|||
|
{
|
|||
|
putc ('t', asmfile);
|
|||
|
TREE_ASM_WRITTEN (TYPE_NAME (type)) = 1;
|
|||
|
}
|
|||
|
dbxout_type (type, 1);
|
|||
|
dbxout_finish_symbol ();
|
|||
|
|
|||
|
/* Change by Bryan Boreham, Kewill, Fri Sep 22 16:57:42 1989.
|
|||
|
Added to make sure all fully-output structs have typedefs. */
|
|||
|
|
|||
|
if (!ANON_AGGRNAME_P (TREE_PURPOSE (link))
|
|||
|
&& (TREE_CODE (TYPE_NAME (type)) != TYPE_DECL
|
|||
|
|| DECL_NAME (TYPE_NAME (type)) != TREE_PURPOSE (link)))
|
|||
|
{
|
|||
|
fprintf (asmfile, ".stabs \"%s:t",
|
|||
|
IDENTIFIER_POINTER (TREE_PURPOSE (link)));
|
|||
|
|
|||
|
current_sym_code = N_LSYM;
|
|||
|
|
|||
|
dbxout_type (type, 1);
|
|||
|
dbxout_finish_symbol ();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Output everything about a symbol block (that is to say, a LET_STMT node
|
|||
|
that represents a scope level),
|
|||
|
including recursive output of contained blocks.
|
|||
|
|
|||
|
STMT is the LET_STMT node.
|
|||
|
DEPTH is its depth within containing symbol blocks.
|
|||
|
ARGS is usually zero; but for the outermost block of the
|
|||
|
body of a function, it is a chain of PARM_DECLs for the function parameters.
|
|||
|
We output definitions of all the register parms
|
|||
|
as if they were local variables of that block.
|
|||
|
|
|||
|
Actually, STMT may be several statements chained together.
|
|||
|
We handle them all in sequence. */
|
|||
|
|
|||
|
static void
|
|||
|
dbxout_block (stmt, depth, args)
|
|||
|
register tree stmt;
|
|||
|
int depth;
|
|||
|
tree args;
|
|||
|
{
|
|||
|
int blocknum;
|
|||
|
|
|||
|
while (stmt)
|
|||
|
{
|
|||
|
switch (TREE_CODE (stmt))
|
|||
|
{
|
|||
|
case COMPOUND_STMT:
|
|||
|
case LOOP_STMT:
|
|||
|
dbxout_block (STMT_BODY (stmt), depth, 0);
|
|||
|
break;
|
|||
|
|
|||
|
case IF_STMT:
|
|||
|
dbxout_block (STMT_THEN (stmt), depth, 0);
|
|||
|
dbxout_block (STMT_ELSE (stmt), depth, 0);
|
|||
|
break;
|
|||
|
|
|||
|
case LET_STMT:
|
|||
|
/* Ignore LET_STMTs for blocks never really used to make RTL. */
|
|||
|
if (! TREE_USED (stmt))
|
|||
|
break;
|
|||
|
/* In dbx format, the syms of a block come before the N_LBRAC. */
|
|||
|
dbxout_tags (STMT_TYPE_TAGS (stmt));
|
|||
|
dbxout_syms (STMT_VARS (stmt));
|
|||
|
if (args)
|
|||
|
dbxout_reg_parms (args);
|
|||
|
|
|||
|
/* Now output an N_LBRAC symbol to represent the beginning of
|
|||
|
the block. Use the block's tree-walk order to generate
|
|||
|
the assembler symbols LBBn and LBEn
|
|||
|
that final will define around the code in this block. */
|
|||
|
if (depth > 0)
|
|||
|
{
|
|||
|
char buf[20];
|
|||
|
blocknum = next_block_number++;
|
|||
|
ASM_GENERATE_INTERNAL_LABEL (buf, "LBB", blocknum);
|
|||
|
|
|||
|
if (TREE_LANG_FLAG_1 (stmt) == 0
|
|||
|
&& TREE_LANG_FLAG_2 (stmt) == 1)
|
|||
|
{
|
|||
|
/* A catch block. Must precede N_LBRAC. */
|
|||
|
tree decl = STMT_VARS (stmt);
|
|||
|
char *name = DECL_NAME (decl) == NULL_TREE
|
|||
|
? "default" : EXCEPTION_NAME_LENGTH + IDENTIFIER_POINTER (DECL_NAME (decl));
|
|||
|
fprintf (asmfile, ".stabs \"%s:C1\",%d,0,0,", name, N_CATCH);
|
|||
|
assemble_name (asmfile, buf);
|
|||
|
fprintf (asmfile, "\n");
|
|||
|
}
|
|||
|
|
|||
|
fprintf (asmfile, ".stabn %d,0,0,", N_LBRAC);
|
|||
|
assemble_name (asmfile, buf);
|
|||
|
fprintf (asmfile, "\n");
|
|||
|
}
|
|||
|
|
|||
|
/* Output the subblocks. */
|
|||
|
dbxout_block (STMT_SUBBLOCKS (stmt), depth + 1, 0);
|
|||
|
|
|||
|
/* Refer to the marker for the end of the block. */
|
|||
|
if (depth > 0)
|
|||
|
{
|
|||
|
char buf[20];
|
|||
|
ASM_GENERATE_INTERNAL_LABEL (buf, "LBE", blocknum);
|
|||
|
fprintf (asmfile, ".stabn %d,0,0,", N_RBRAC);
|
|||
|
assemble_name (asmfile, buf);
|
|||
|
fprintf (asmfile, "\n");
|
|||
|
}
|
|||
|
}
|
|||
|
stmt = TREE_CHAIN (stmt);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Output dbx data for a function definition.
|
|||
|
This includes a definition of the function name itself (a symbol),
|
|||
|
definitions of the parameters (locating them in the parameter list)
|
|||
|
and then output the block that makes up the function's body
|
|||
|
(including all the auto variables of the function). */
|
|||
|
|
|||
|
void
|
|||
|
dbxout_function (decl)
|
|||
|
tree decl;
|
|||
|
{
|
|||
|
extern tree value_identifier;
|
|||
|
|
|||
|
dbxout_symbol (decl, 0);
|
|||
|
dbxout_parms (DECL_ARGUMENTS (decl));
|
|||
|
if (DECL_NAME (DECL_RESULT (decl)) != value_identifier)
|
|||
|
dbxout_symbol (DECL_RESULT (decl), 1);
|
|||
|
dbxout_block (DECL_INITIAL (decl), 0, DECL_ARGUMENTS (decl));
|
|||
|
|
|||
|
/* If we made any temporary types in this fn that weren't
|
|||
|
output, output them now. */
|
|||
|
dbxout_types (get_temporary_types ());
|
|||
|
}
|
|||
|
|
|||
|
/* GNU C++ extensions. */
|
|||
|
|
|||
|
/* At the start of the file, emit symbolic information to orient
|
|||
|
GDB for this particular file's exception handling implementation.
|
|||
|
EH_TYPE is the type name of the exception type.
|
|||
|
EH_DECL is the global root of the exception handler stack. */
|
|||
|
|
|||
|
void
|
|||
|
dbxout_eh_init (eh_type, eh_decl)
|
|||
|
tree eh_type, eh_decl;
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
#else /* not DBX_DEBUGGING_INFO */
|
|||
|
|
|||
|
void
|
|||
|
dbxout_init (asm_file, input_file_name)
|
|||
|
FILE *asm_file;
|
|||
|
char *input_file_name;
|
|||
|
{}
|
|||
|
|
|||
|
void
|
|||
|
dbxout_symbol (decl, local)
|
|||
|
tree decl;
|
|||
|
int local;
|
|||
|
{}
|
|||
|
|
|||
|
void
|
|||
|
dbxout_types (types)
|
|||
|
register tree types;
|
|||
|
{}
|
|||
|
|
|||
|
void
|
|||
|
dbxout_tags (tags)
|
|||
|
tree tags;
|
|||
|
{}
|
|||
|
|
|||
|
void
|
|||
|
dbxout_function (decl)
|
|||
|
tree decl;
|
|||
|
{}
|
|||
|
|
|||
|
void
|
|||
|
dbxout_eh_init (eh_type, eh_decl)
|
|||
|
tree eh_type, eh_decl;
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
#endif /* DBX_DEBUGGING_INFO */
|