diff options
| author | Andrew Lee <alee14498@protonmail.com> | 2021-08-15 00:34:05 -0400 |
|---|---|---|
| committer | Andrew Lee <alee14498@protonmail.com> | 2021-08-15 00:34:05 -0400 |
| commit | 60cc83bf91bfc9bb02f6304b5d6c8234ba6d210f (patch) | |
| tree | fdc0be85a1ca35e34c3ae2c805fe9b718e3c1091 /gcc-1.40/symout.c | |
| parent | dd8dfab51b832a654365ed00c06bf802ff628bfa (diff) | |
| download | linux-0.01-distro-60cc83bf91bfc9bb02f6304b5d6c8234ba6d210f.tar.gz linux-0.01-distro-60cc83bf91bfc9bb02f6304b5d6c8234ba6d210f.tar.bz2 linux-0.01-distro-60cc83bf91bfc9bb02f6304b5d6c8234ba6d210f.zip | |
Diffstat (limited to 'gcc-1.40/symout.c')
| -rw-r--r-- | gcc-1.40/symout.c | 1267 |
1 files changed, 1267 insertions, 0 deletions
diff --git a/gcc-1.40/symout.c b/gcc-1.40/symout.c new file mode 100644 index 0000000..e6ed44a --- /dev/null +++ b/gcc-1.40/symout.c @@ -0,0 +1,1267 @@ +/* Output GDB-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. */ + + +#include "config.h" +#include "tree.h" +#include "symseg.h" +#include "rtl.h" +#include "gdbfiles.h" +#include <stdio.h> +#undef NULL +/* <...> used here so one can prevent use of ./stddef.h + by changing the -I options used. */ +#include <stddef.h> + +/* Get N_SO from stab.h if we can expect the file to exist. */ +#ifdef DBX_DEBUGGING_INFO +#ifdef USG +#include "gstab.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 */ +#endif + +/* .stabs code for source file name. */ +#ifndef N_SO +#define N_SO 0x64 +#endif + +/* Unix maximum on file name length. Needed for getwd. */ +#define MAXNAMLEN 1024 + +/* Get the number to output for a reference to type TYPE. */ +#define TYPE_OUTPUT_ADDRESS(TYPE) \ + TYPE_SYMTAB_ADDRESS (TYPE_MAIN_VARIANT (TYPE)) + +/* Stream for writing symbol table file. */ +static FILE *symfile; + +/* Name of symbol table file. */ +static char *symfile_name; + +/* Stream for writing to assembler file. */ +static FILE *asmfile; + +/* Address for allocating space in symbol table file. + Changes in this variable are paired globally with writes to symfile, + but often we allocate many structures, advancing next_address, + before writing any of them. */ +static int next_address; + +/* Chain recording all the types that have been output, + giving the address-in-the-symseg of each one. */ + +struct typevec_elt +{ + int address; + struct typevec_elt *next; +}; + +static struct typevec_elt *typevec; + +/* Number of types recorded so far in the chain. */ + +static int total_types; + +/* Lists of types to which forward references have been made. + Separate lists for temporary and permanent types. */ + +static tree temporary_fwd_refs; +static tree permanent_fwd_refs; + +/* `blockvec' is a chain recording all the symbol-blocks that have been output, + giving the address-in-the-symseg of each one. */ + +struct blockvec_elt +{ + int address; + struct blockvec_elt *next; +}; + +static struct blockvec_elt *blockvec; + +/* Number of blocks recorded so far in the chain. */ + +static int total_blocks; + +static void symout_range_bounds (); +static void symout_array_domain (); +static void symout_record_fields (); +static void symout_enum_values (); +static void symout_record_field_names (); +static void symout_enum_value_names (); +static int subrange_p (); +static void symout_strings_skip (); +static void symout_strings_print (); + +/* At the beginning of compilation, start writing the symbol table. + Initialize the type and block chain. + Also open and initialize the symseg file. */ + +void +symout_init (filename, asm_file, sourcename) + char *filename; + FILE *asm_file; + char *sourcename; +{ + struct symbol_root buffer; + +#ifdef VMS + fatal ("Cannot write GDB debugging format on VMS"); +#endif + + asmfile = asm_file; + fprintf (asmfile, ".text 0\n.gdbbeg 0\n.gdbbeg 1\n"); + fprintf (asmfile, + "Ltext:\t.stabs \"%s\",%d,0,0,Ltext\n", + sourcename, N_SO); + fprintf (asmfile, ".data 0\nLdata:\n"); + ASM_OUTPUT_LOCAL (asmfile, "Lbss", 0, 0); + fprintf (asmfile, ".gdbsym Ldata,%d\n", + (char *) &buffer.databeg - (char *) &buffer); + fprintf (asmfile, ".gdbsym Lbss,%d\n", + (char *) &buffer.bssbeg - (char *) &buffer); + + symfile = fopen (filename, "w"); + if (symfile == 0) + pfatal_with_name (filename); + symfile_name = (char *) malloc (strlen (filename) + 1); + strcpy (symfile_name, filename); + + typevec = 0; + blockvec = 0; + total_types = 0; + total_blocks = 0; + + permanent_fwd_refs = 0; + temporary_fwd_refs = 0; + + bzero (&buffer, sizeof buffer); + fwrite (&buffer, sizeof buffer, 1, symfile); + + next_address = sizeof buffer; +} + +/* Functions for outputting strings into the symbol table. + The string to be output is effectively the concatenation of + the two strings P1 and P2. Their lengths are given as S1 and S2. + If P1 or P2 is zero, that string is not used. + + A null character is output to terminate the string, + and it is followed by more nulls as padding to a word boundary. */ + +static void +symout_strings (p1, s1, p2, s2) + char *p1; + int s1; + char *p2; + int s2; +{ + symout_strings_print (p1, s1, p2, s2); + symout_strings_skip (p1, s1, p2, s2); +} + +/* Like symout_strings but only output; do not update next_address. */ + +static void +symout_strings_print (p1, s1, p2, s2) + char *p1; + int s1; + char *p2; + int s2; +{ + register int total; + + if (p1 && s1 == 0) + s1 = strlen (p1); + if (p2 && s2 == 0) + s2 = strlen (p2); + + if (p1) + fwrite (p1, s1, 1, symfile); + if (p2) + fwrite (p2, s2, 1, symfile); + putc (0, symfile); + + total = s1 + s2 + 1; + while (total % sizeof (int)) + { + putc (0, symfile); + total++; + } +} + +/* Like symout_strings but just update next_address; do not output. */ + +static void +symout_strings_skip (p1, s1, p2, s2) + char *p1; + int s1; + char *p2; + int s2; +{ + register int total; + + if (p1 && s1 == 0) + s1 = strlen (p1); + if (p2 && s2 == 0) + s2 = strlen (p2); + + total = s1 + s2 + 1; + while (total % sizeof (int)) + total++; + + next_address += total; +} + +/* Call here to output a chain of types. + After each function, this is done first for the chain of permanent types + made during the function, and then for the chain of temporary types. + This must be done before outputting the symbols and blocks of the function. + + At the end of compilation, this is done for all the permanent types + made since the last function. + + Each permanent type is done once, at the beginning of the next function, + or at the end of the compilation if no functions follow. + Once a type has been processed here, its TYPE_SYMTAB_ADDRESS remains + set up. */ + +void +symout_types (types) + tree types; +{ + struct typerec + { + int number; + int address; + int nfields; + int fields_address; + int name_address; + char *name; + char *name_prefix; + }; + + register int n_types, i; + register struct typerec *records; + register tree next; + struct type buffer; + int this_run_address = next_address; + + /* Count the number of types to be handled here. */ + + for (next = types, n_types = 0; + next; + next = TREE_CHAIN (next), n_types++); + + records = (struct typerec *) alloca (n_types * sizeof (struct typerec)); + + /* Compute the amount of space each type needs, updating next_address + and storing the address of the data for each type. */ + + for (next = types, i = 0; + next; + next = TREE_CHAIN (next), i++) + { + register struct typevec_elt *velt + = (struct typevec_elt *) xmalloc (sizeof (struct typevec_elt)); + velt->next = typevec; + typevec = velt; + + total_types++; + + if (TYPE_NAME (next)) + { + records[i].name_address = next_address; + + if (TREE_CODE (TYPE_NAME (next)) == IDENTIFIER_NODE) + { + records[i].name = IDENTIFIER_POINTER (TYPE_NAME (next)); + switch (TREE_CODE (next)) + { + case RECORD_TYPE: + records[i].name_prefix = "struct "; + break; + + case UNION_TYPE: + records[i].name_prefix = "union "; + break; + + case ENUMERAL_TYPE: + records[i].name_prefix = "enum "; + break; + } + } + else + { + records[i].name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (next))); + records[i].name_prefix = 0; + } + symout_strings_skip (records[i].name_prefix, 0, + records[i].name, 0); + + } + else + { + records[i].name = 0; + records[i].name_address = 0; + records[i].name_prefix = 0; + } + + /* If this type was forward-referenced from a previous call + to symout_types, store this type's address into the reference. */ + if (TYPE_POINTER_TO (next) != 0 + && TYPE_SYMTAB_ADDRESS (TYPE_POINTER_TO (next)) != 0 + && TYPE_SYMTAB_ADDRESS (TYPE_POINTER_TO (next)) < this_run_address) + { + int pos = ftell (symfile); + int myaddr = next_address; + fflush (symfile); + fseek (symfile, + (TYPE_SYMTAB_ADDRESS (TYPE_POINTER_TO (next)) + + offsetof (struct type, target_type)), + 0); + fwrite (&myaddr, sizeof (int), 1, symfile); + fflush (symfile); + fseek (symfile, pos, 0); + } + + records[i].address = next_address; + TYPE_SYMTAB_ADDRESS (next) = next_address; + velt->address = next_address; + next_address += sizeof (struct type); + records[i].nfields = 0; + records[i].fields_address = 0; + switch (TREE_CODE (next)) + { + case ARRAY_TYPE: + records[i].nfields + = (TYPE_DOMAIN(next) + ? ! integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (next))) + : 0 ); + break; + + case INTEGER_TYPE: + if (subrange_p (next)) + buffer.nfields = 2; + break; + + case RECORD_TYPE: + case UNION_TYPE: + case ENUMERAL_TYPE: + records[i].nfields = list_length (TYPE_FIELDS (next)); + } + if (records[i].nfields) + records[i].fields_address = next_address; + next_address += records[i].nfields * sizeof (struct field); + } + + /* Now write the data whose space we have assigned. + First fill the data into BUFFER, then write BUFFER. */ + + for (next = types, i = 0; + next; + next = TREE_CHAIN (next), i++) + { + if (records[i].name) + symout_strings_print (records[i].name_prefix, 0, + records[i].name, 0); + + if (TREE_TYPE (next) != 0 && TYPE_OUTPUT_ADDRESS (TREE_TYPE (next)) == 0) + { + /* We are making a forward-reference to our target type. + Make a list of all of these. */ + if (TREE_PERMANENT (next)) + permanent_fwd_refs + = perm_tree_cons (TREE_TYPE (next), 0, permanent_fwd_refs); + else + temporary_fwd_refs + = tree_cons (TREE_TYPE (next), 0, temporary_fwd_refs); + } + + if (TYPE_SIZE (next) == 0) + buffer.length = 0; + else + buffer.length + = (TREE_INT_CST_LOW (TYPE_SIZE (next)) + * TYPE_SIZE_UNIT (next) / BITS_PER_UNIT); + + buffer.name = (char *) records[i].name_address; + buffer.target_type = (struct type *) (TREE_TYPE (next) ? TYPE_OUTPUT_ADDRESS (TREE_TYPE (next)) : 0); + + buffer.pointer_type = 0; + buffer.function_type = 0; + buffer.flags + = ((TREE_CODE (next) == INTEGER_TYPE || TREE_CODE (next) == ENUMERAL_TYPE) + && TREE_UNSIGNED (next)) + ? TYPE_FLAG_UNSIGNED : 0; + buffer.nfields = records[i].nfields; + buffer.fields = (struct field *) records[i].fields_address; + + switch (TREE_CODE (next)) + { + case INTEGER_TYPE: + buffer.code = TYPE_CODE_INT; + if (buffer.nfields) + buffer.code = TYPE_CODE_RANGE; + break; + + case REAL_TYPE: + buffer.code = TYPE_CODE_FLT; + break; + + case VOID_TYPE: + buffer.code = TYPE_CODE_VOID; + break; + + case POINTER_TYPE: + buffer.code = TYPE_CODE_PTR; + break; + + case ARRAY_TYPE: + if (buffer.nfields == 0) + buffer.code = TYPE_CODE_ARRAY; + else + buffer.code = TYPE_CODE_PASCAL_ARRAY; + break; + + case RECORD_TYPE: + buffer.code = TYPE_CODE_STRUCT; + break; + + case UNION_TYPE: + buffer.code = TYPE_CODE_UNION; + break; + + case FUNCTION_TYPE: + buffer.code = TYPE_CODE_FUNC; + break; + + case ENUMERAL_TYPE: + buffer.code = TYPE_CODE_ENUM; + break; + + default: + abort (); + } + + fwrite (&buffer, sizeof buffer, 1, symfile); + + /* Now write the `struct field's that certain kinds of type have. + This allocates space for the names of those fields, + incrementing next_address for the names. */ + + switch (TREE_CODE (next)) + { + case ARRAY_TYPE: + if (buffer.nfields) + symout_array_domain (next); + break; + + case RECORD_TYPE: + case UNION_TYPE: + symout_record_fields (next); + break; + + case ENUMERAL_TYPE: + symout_enum_values (next); + break; + + case INTEGER_TYPE: + if (buffer.nfields) + symout_range_bounds (next); + } + } + + /* Now output the strings referred to by the fields of certain types. + (next_address was already updated for these strings.) */ + + for (next = types, i = 0; + next; + next = TREE_CHAIN (next), i++) + { + switch (TREE_CODE (next)) + { + case RECORD_TYPE: + case UNION_TYPE: + symout_record_field_names (next); + break; + + case ENUMERAL_TYPE: + symout_enum_value_names (next); + break; + } + } +} + +/* Given a list of types TYPES, return a chain of just those + that haven't been written in the symbol table. */ + +static tree +filter_undefined_types (types) + tree types; +{ + tree new = 0; + tree next; + + for (next = types; next; next = TREE_CHAIN (next)) + if (TYPE_SYMTAB_ADDRESS (TREE_PURPOSE (next)) == 0) + { + TREE_CHAIN (TREE_PURPOSE (next)) = new; + new = TREE_PURPOSE (next); + } + + return new; +} + +/* Return nonzero if TYPE's range of possible values + is not the full range allowed by the number of bits it has. + TYPE is assumed to be an INTEGER_TYPE or ENUMERAL_TYPE. */ + +static int +subrange_p (type) + tree type; +{ + int uns = TREE_UNSIGNED (type); + + if (TYPE_PRECISION (type) >= HOST_BITS_PER_INT) + { + if (uns) + return integer_zerop (TYPE_MIN_VALUE (type)) + && TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) == 0 + && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (type)) + == (1 << (TYPE_PRECISION (type) - HOST_BITS_PER_INT)) - 1); + return TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) == 0 + && TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) == 0 + && (TREE_INT_CST_HIGH (TYPE_MIN_VALUE (type)) + == (-1) << (TYPE_PRECISION (type) - 1 - HOST_BITS_PER_INT)) + && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (type)) + == (1 << (TYPE_PRECISION (type) - 1 - HOST_BITS_PER_INT)) - 1); + } + + if (uns) + { + int mask; + + if (TYPE_PRECISION (type) == HOST_BITS_PER_INT) + /* Shifting by 32 loses on some machines. */ + mask = -1; + else + mask = (1 << TYPE_PRECISION (type)) - 1; + + return (integer_zerop (TYPE_MIN_VALUE (type)) + && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) == mask)); + } + else + return ((TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + == (-1) << (TYPE_PRECISION (type) - 1)) + && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) + == (1 << (TYPE_PRECISION (type) - 1)) - 1)); +} + +/* Functions to output the "fields" of various kinds of types. + These assume that next_address has already been incremented to + cover these fields, and the fields of all the other types being + output in this batch; so next_address can be used to allocate + space to store field names, etc. */ + +static void +symout_array_domain (type) + tree type; +{ + struct field buffer; + + buffer.bitpos = 0; + buffer.bitsize = 0; + buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TYPE_DOMAIN (type)); + buffer.name = 0; + fwrite (&buffer, sizeof (struct field), 1, symfile); +} + +static void +symout_range_bounds (type) + tree type; +{ + struct field buffer; + + buffer.bitpos = TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)); + buffer.bitsize = 0; + buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (type); + buffer.name = 0; + fwrite (&buffer, sizeof (struct field), 1, symfile); + + buffer.bitpos = TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)); + buffer.bitsize = 0; + buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (type); + buffer.name = 0; + fwrite (&buffer, sizeof (struct field), 1, symfile); +} + +static void +symout_record_fields (type) + tree type; +{ + struct field buffer; + register tree field; + + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + buffer.bitpos = DECL_OFFSET (field); + buffer.bitsize + = (TREE_PACKED (field) + ? TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field) + : 0); + buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TREE_TYPE (field)); + if (DECL_NAME (field)) + { + buffer.name = (char *) next_address; + symout_strings_skip (0, IDENTIFIER_LENGTH (DECL_NAME (field)), 0, 0); + } + else + buffer.name = 0; + fwrite (&buffer, sizeof (struct field), 1, symfile); + } +} + +static void +symout_enum_values (type) + tree type; +{ + struct field buffer; + register tree link, value; + + for (link = TYPE_VALUES (type); link; link = TREE_CHAIN (link)) + { + value = TREE_VALUE (link); + buffer.bitpos = TREE_INT_CST_LOW (value); + buffer.bitsize = 0; + buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (type); + buffer.name = (char *) next_address; + symout_strings_skip (0, IDENTIFIER_LENGTH (TREE_PURPOSE (link)), 0, 0); + fwrite (&buffer, sizeof buffer, 1, symfile); + } +} + +/* Output field names or value names for the fields of a type. + This is called, for the types that need it, after the fields + have been output for all the types in the batch. + We do not update next_address here, because it has already been + updated for all the names in all the fields in all the types. */ + +static void +symout_record_field_names (type) + tree type; +{ + register tree field; + + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + if (DECL_NAME (field)) + symout_strings_print (IDENTIFIER_POINTER (DECL_NAME (field)), + IDENTIFIER_LENGTH (DECL_NAME (field)), + 0, 0); +} + +static void +symout_enum_value_names (type) + tree type; +{ + register tree value; + + for (value = TYPE_VALUES (type); value; value = TREE_CHAIN (value)) + symout_strings_print (IDENTIFIER_POINTER (TREE_PURPOSE (value)), + IDENTIFIER_LENGTH (TREE_PURPOSE (value)), + 0, 0); +} + +/* Output the symbols of a block, given the list of decl nodes. + Store the file addresses at which the symbols are output + into ADDR_BUFFER, a vector which has just the right length. + + If FILTER is 1, do only the private symbols in DECLS. + If FILTER is 2, do only the public ones (but no externals). + If FILTER is 0, do all (except external functions). */ + +static void +symout_block_symbols (decls, addr_buffer, filter) + tree decls; + int *addr_buffer; + int filter; +{ + register tree decl; + struct symbol buffer; + register int i; + + for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl)) + { + register int name_address = next_address; + + if (filter == (TREE_PUBLIC (decl) ? 1 : 2)) + continue; + + /* Do not mention external functions. + Let their own files mention them. + In the top blocks, don't mention external anything. */ + + if (TREE_EXTERNAL (decl) + && (filter || TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)) + continue; + + if (TREE_TYPE (decl) == error_mark_node) + continue; + + symout_strings (IDENTIFIER_POINTER (DECL_NAME (decl)), + IDENTIFIER_LENGTH (DECL_NAME (decl)), + 0, 0); + addr_buffer[i] = next_address; + buffer.name = (char *) name_address; + buffer.namespace = VAR_NAMESPACE; + buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TREE_TYPE (decl)); + switch (TREE_CODE (decl)) + { + case PARM_DECL: + buffer.class = LOC_ARG; + buffer.value.value = DECL_OFFSET (decl) / BITS_PER_UNIT; + break; + + case VAR_DECL: + case RESULT_DECL: + if (TREE_STATIC (decl) || TREE_EXTERNAL (decl)) + { + if (! TREE_PUBLIC (decl) || DECL_INITIAL (decl)) + { + char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0); + fprintf (asmfile, "\t.gdbsym "); + ASM_OUTPUT_LABELREF (asmfile, str); + fprintf (asmfile, ",%d\n", + next_address + (char *)&buffer.value - (char *)&buffer); + buffer.class = LOC_STATIC; + } + else + /* Uninitialized public symbols are output as .comm; + Tell GDB to get address from loader global symbol. + Also come here for symbols declared extern. */ + buffer.class = LOC_EXTERNAL; + } + else + { + if (GET_CODE (DECL_RTL (decl)) == REG) + { + buffer.class = LOC_REGISTER; + buffer.value.value = REGNO (DECL_RTL (decl)); + /* Detect vars that were optimized entirely away. */ + if (buffer.value.value == -1) + buffer.class = LOC_CONST; + } + 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. + If we have a pointer-type (which we should, for an array), + output the variable as a pointer. + Otherwise ignore it, since it is hard to create the ptr + type now and output it, and -gg is being retired. */ + { + tree ptype = TYPE_POINTER_TO (TREE_TYPE (TREE_TYPE (decl))); + if (ptype == 0 + || TYPE_OUTPUT_ADDRESS (ptype) == 0) + continue; + + buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (ptype); + + + if (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG) + { + buffer.class = LOC_REGISTER; + buffer.value.value = REGNO (DECL_RTL (decl)); + /* Detect vars that were optimized entirely away. */ + if (buffer.value.value == -1) + buffer.class = LOC_CONST; + } + else + { + register rtx addr = XEXP (DECL_RTL (decl), 0); + if (GET_CODE (addr) != PLUS && GET_CODE (addr) != MINUS) + abort (); + if (GET_CODE (XEXP (addr, 1)) != CONST_INT) + abort (); + buffer.class = LOC_LOCAL; + buffer.value.value = INTVAL (XEXP (addr, 1)); + if (GET_CODE (addr) == MINUS) + buffer.value.value = - buffer.value.value; + } + } + /* Locals in memory are expected to be addressed as + (PLUS (REG ...) (CONST_INT ...)). + Bomb out if that is not so. */ + else if (GET_CODE (DECL_RTL (decl)) == MEM) + { + register rtx addr = XEXP (DECL_RTL (decl), 0); + if (GET_CODE (addr) != PLUS && GET_CODE (addr) != MINUS) + abort (); + if (GET_CODE (XEXP (addr, 1)) != CONST_INT) + abort (); + buffer.class = LOC_LOCAL; + buffer.value.value = INTVAL (XEXP (addr, 1)); + if (GET_CODE (addr) == MINUS) + buffer.value.value = - buffer.value.value; + } + else + abort (); + } + break; + + case TYPE_DECL: + buffer.class = LOC_TYPEDEF; + buffer.value.value = 0; + break; + + case CONST_DECL: + buffer.class = LOC_CONST; + buffer.value.value = TREE_INT_CST_LOW (DECL_INITIAL (decl)); + break; + + case FUNCTION_DECL: + if (DECL_INITIAL (decl)) + { + buffer.class = LOC_BLOCK; + buffer.value.value = DECL_BLOCK_SYMTAB_ADDRESS (decl); + } + else + buffer.class = LOC_EXTERNAL; + } + + fwrite (&buffer, sizeof buffer, 1, symfile); + next_address += sizeof buffer; + i++; + } +} + +/* Output the tags (struct, union and enum definitions) for a block, + given a list of them (a chain of TREE_LIST nodes) in TAGS. + Store their addresses in the file into ADDR_BUFFER. */ + +static void +symout_block_tags (tags, addr_buffer) + tree tags; + int *addr_buffer; +{ + register tree tag; + struct symbol buffer; + register int i; + + for (tag = tags, i = 0; tag; tag = TREE_CHAIN (tag), i++) + { + buffer.name = (char *) next_address; + + symout_strings (IDENTIFIER_POINTER (TREE_PURPOSE (tag)), + IDENTIFIER_LENGTH (TREE_PURPOSE (tag)), + 0, 0); + addr_buffer[i] = next_address; + buffer.namespace = STRUCT_NAMESPACE; + buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TREE_VALUE (tag)); + buffer.class = LOC_TYPEDEF; + buffer.value.value = 0; + + fwrite (&buffer, sizeof buffer, 1, symfile); + next_address += sizeof buffer; + } +} + +/* Output all the data structure for a "block" + (any binding contour). + DECLS is the chain of declarations of variables in this block. + TAGS is the list of struct, union and enum tag definitions of this block. + SUPERBLOCK_ADDRESS is the symtab file address of the containing block's + data structure. */ + +int +symout_block (decls, tags, args, superblock_address) + tree decls; + tree tags; + tree args; + int superblock_address; +{ + register tree decl; + register int i; + register int *addr_buffer; + struct block buffer; + int n_decls, n_tags, n_args, total; + register struct blockvec_elt *velt; + int block_address; + + for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl)) + if (! TREE_EXTERNAL (decl) + || TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE) + i++; + + n_decls = i; + + for (decl = args, i = 0; decl; decl = TREE_CHAIN (decl), i++); + n_args = i; + + for (decl = tags, i = 0; decl; decl = TREE_CHAIN (decl), i++); + n_tags = i; + + total = n_decls + n_args + n_tags; + + addr_buffer = (int *) alloca (total * sizeof (int)); + + symout_block_symbols (args, addr_buffer, 0); + symout_block_symbols (decls, addr_buffer + n_args, 0); + symout_block_tags (tags, addr_buffer + n_decls + n_args); + + velt = (struct blockvec_elt *) xmalloc (sizeof (struct blockvec_elt)); + velt->next = blockvec; + velt->address = next_address; + blockvec = velt; + + buffer.startaddr = 0; + buffer.endaddr = 0; + buffer.superblock = (struct block *) superblock_address; + buffer.function = 0; + buffer.nsyms = total; + + block_address = next_address; + fwrite (&buffer, sizeof buffer - sizeof buffer.sym, 1, symfile); + next_address += sizeof buffer - sizeof buffer.sym; + + fwrite (addr_buffer, sizeof (int), total, symfile); + next_address += total * sizeof (int); + + fprintf (asmfile, "\t.gdbblock %d,%d\n", total_blocks + 2, block_address); + total_blocks++; + + return block_address; +} + +/* Walk STMT, the body of a function, and output symtab data on + all the blocks that compose it and all symbols inside them. + ARGS is a chain of decls for argument variables of the function. + SUPERBLOCK_ADDRESS is the address of symbol data for the + innermost block containing STMT; it is used for recursive calls, + and is always 0 for the outermost call (since the containing + block for a function is output later than the function). */ + +int +symout_function (stmt, args, superblock_address) + register tree stmt; + tree args; + int superblock_address; +{ + int address = superblock_address; + + while (stmt) + { + switch (TREE_CODE (stmt)) + { + case COMPOUND_STMT: + case LOOP_STMT: + symout_function (STMT_BODY (stmt), 0, address); + break; + + case IF_STMT: + symout_function (STMT_THEN (stmt), 0, address); + symout_function (STMT_ELSE (stmt), 0, address); + break; + + case LET_STMT: + /* Ignore LET_STMTs for blocks never really used to make RTL. */ + if (! TREE_USED (stmt)) + break; + address = + symout_block (STMT_VARS (stmt), STMT_TYPE_TAGS (stmt), args, + superblock_address); + + symout_function (STMT_SUBBLOCKS (stmt), 0, address); + } + stmt = TREE_CHAIN (stmt); + } + return address; +} + +symout_function_end () +{ + /* Output dummy entries for any undefined structure references. */ + symout_types (filter_undefined_types (temporary_fwd_refs)); + temporary_fwd_refs = 0; +} + +/* Output all the data structure for a top two blocks in a compilation. + The top block is for public (global) symbols; + the next one is for private (this file only) symbols. + + DECLS is the chain of declarations of variables in this block. + TAGS is the list of struct, union and enum tag definitions. */ + +void +symout_top_blocks (decls, tags) + tree decls; + tree tags; +{ + register tree decl; + register int i; + register int *addr_buffer; + struct block buffer; + int n_decls, n_tags; + register struct blockvec_elt *velt; + int top_block_addr; + + /* First do the public-symbols block. */ + + for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl)) + if (TREE_PUBLIC (decl) && ! TREE_EXTERNAL (decl)) + i++; + n_decls = i; + + addr_buffer = (int *) alloca (n_decls * sizeof (int)); + + symout_block_symbols (decls, addr_buffer, 2); + + fprintf (asmfile, ".text 0\n\t.gdbend 0\n"); + fprintf (asmfile, "\t.gdbblock 0,%d\n", next_address); + + total_blocks++; + velt = (struct blockvec_elt *) xmalloc (sizeof (struct blockvec_elt)); + velt->next = blockvec; + velt->address = next_address; + blockvec = velt; + + top_block_addr = next_address; + + buffer.startaddr = 0; + buffer.endaddr = 0; + buffer.superblock = 0; + buffer.function = 0; + buffer.nsyms = n_decls;; + + fwrite (&buffer, sizeof buffer - sizeof buffer.sym, 1, symfile); + next_address += sizeof buffer - sizeof buffer.sym; + + fwrite (addr_buffer, sizeof (int), n_decls, symfile); + next_address += n_decls * sizeof (int); + + /* Next do the private-symbols block. */ + + for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl)) + if (! TREE_PUBLIC (decl) && ! TREE_EXTERNAL (decl)) + i++; + n_decls = i; + + for (decl = tags, i = 0; decl; decl = TREE_CHAIN (decl), i++); + n_tags = i; + + addr_buffer = (int *) alloca ((n_decls + n_tags) * sizeof (int)); + + symout_block_symbols (decls, addr_buffer, 1); + symout_block_tags (tags, addr_buffer + n_decls); + + fprintf (asmfile, "\t.gdbend 1\n"); + fprintf (asmfile, "\t.gdbblock 1,%d\n", next_address); + + total_blocks++; + velt = (struct blockvec_elt *) xmalloc (sizeof (struct blockvec_elt)); + velt->next = blockvec; + velt->address = next_address; + blockvec = velt; + + buffer.startaddr = 0; + buffer.endaddr = 0; + buffer.superblock = (struct block *) top_block_addr; + buffer.function = 0; + buffer.nsyms = n_decls + n_tags;; + + fwrite (&buffer, sizeof buffer - sizeof buffer.sym, 1, symfile); + next_address += sizeof buffer - sizeof buffer.sym; + + fwrite (addr_buffer, sizeof (int), n_decls + n_tags, symfile); + next_address += (n_decls + n_tags) * sizeof (int); +} + +/* Output the source-line-number information. */ + +/* Output a `struct source' for the source file described by F. + Return the address-in-the-symseg of the `struct source'. */ + +static int +symout_source_file (f) + struct gdbfile *f; +{ + /* Make the `struct source' big enough for as many lines as + this file has. */ + int size = sizeof (struct source) + (f->nlines - 1) * sizeof (struct line); + struct source *buffer + = (struct source *) alloca (size); + int addr; + + /* Use zero for the line data, since assembler will store the real data. */ + bzero (buffer, size); + + /* Output the file's name as a string. The assembler doesn't know this. */ + buffer->name = (char *) next_address; + symout_strings (f->name, 0, 0, 0); + buffer->nlines = f->nlines; + + /* Write the structure. */ + addr = next_address; + fwrite (buffer, 1, size, symfile); + next_address += size; + + /* Tell assembler where to write the real line-number data. */ + fprintf (asmfile, "\t.gdblinetab %d,%d\n", + f->filenum, addr + sizeof (int)); + + return addr; +} + +/* Output the `struct sourcevector' which describes all the + source files and points a `struct source' for each one. */ + +static int +symout_sources () +{ + register struct gdbfile *f; + int nfiles = 0; + struct sourcevector *s; + int i; + int size; + int addr; + + /* Count number of files to determine size of the sourcevector. */ + for (f = gdbfiles; f; f = f->next) + ++nfiles; + + /* Allocate buffer for the sourcevector and record its length. */ + size = sizeof (int) + nfiles * sizeof (struct source *); + s = (struct sourcevector *) alloca (size); + s->length = nfiles; + + /* Output a `struct source' for each file; put address into sourcevector. */ + for (f = gdbfiles, i = 0; f; f = f->next, i++) + s->source[i] = (struct source *) symout_source_file (f); + + /* Output the sourcevector. */ + addr = next_address; + fwrite (s, 1, size, symfile); + next_address += size; + return addr; +} + +/* Call here at the end of compilation, after outputting all the + blocks and symbols, to output the blockvector and typevector + and close the symbol table file. FILETIME is source file's + creation time. */ + +void +symout_finish (filename, filetime) + char *filename; + int filetime; +{ + int *blockvector = (int *) alloca ((total_blocks + 1) * sizeof (int)); + int *typevector; + int now = time (0); + register int i; + struct symbol_root buffer; + char dir[MAXNAMLEN]; + + /* Output dummy entries for any undefined structure references. */ + symout_types (filter_undefined_types (permanent_fwd_refs)); + + typevector = (int *) alloca ((total_types + 1) * sizeof (int)); + + buffer.language = language_c; + buffer.blockvector = (struct blockvector *) next_address; + + /* The two blocks at the beginning of the chain + are the file's private symbols block and public symbols block. + They belong at the front of the blockvector, in that order. */ + blockvector[2] = blockvec->address; + blockvec = blockvec->next; + blockvector[1] = blockvec->address; + blockvec = blockvec->next; + + /* The rest of the blocks are in the chain in reverse order. */ + for (i = total_blocks; i > 2; i--) + { + blockvector[i] = blockvec->address; + blockvec = blockvec->next; + } + blockvector[0] = total_blocks; + + fwrite (blockvector, sizeof (int), total_blocks + 1, symfile); + next_address += sizeof (int) * (total_blocks + 1); + + buffer.typevector = (struct typevector *) next_address; + + for (i = total_types; i > 0; i--) + { + typevector[i] = typevec->address; + typevec = typevec->next; + } + typevector[0] = total_types; + + fwrite (typevector, sizeof (int), total_types + 1, symfile); + next_address += sizeof (int) * (total_types + 1); + + buffer.sourcevector = (struct sourcevector *) symout_sources (); + + buffer.format = 1; + buffer.textrel = 0; /* These four will be set up by linker. */ + buffer.datarel = 0; /* Make them 0 now, which is right for */ + buffer.bssrel = 0; /* looking at the .o file in gdb. */ + buffer.ldsymoff = 0; + + buffer.version = (char *) next_address; + symout_strings (ctime (&filetime), 0, 0, 0); + + buffer.compilation = (char *) next_address; + symout_strings (ctime (&now), 0, 0, 0); + + buffer.filename = (char *) next_address; + symout_strings (filename, 0, 0, 0); + + buffer.filedir = (char *) next_address; +#ifdef USG + strcpy (dir, getcwd (dir, MAXNAMLEN)); +#else +#ifndef VMS + getwd (dir); +#else + abort (); +#endif +#endif + symout_strings (dir, 0, 0, 0); + + fflush (symfile); + + if (ferror (symfile) != 0) + fatal_io_error (symfile_name); + + buffer.length = next_address; + + if (lseek (fileno (symfile), 0, 0) < 0) + pfatal_with_name (symfile_name); + if (write (fileno (symfile), &buffer, sizeof buffer) < 0) + pfatal_with_name (symfile_name); + close (fileno (symfile)); +} |
