123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993 |
- /* Output GDB-format symbol table information from GNU compiler.
- Copyright (C) 1987 Free Software Foundation, Inc.
- This file is part of GNU CC.
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY. No author or distributor
- accepts responsibility to anyone for the consequences of using it
- or for whether it serves any particular purpose or works at all,
- unless he says so in writing. Refer to the GNU CC General Public
- License for full details.
- Everyone is granted permission to copy, modify and redistribute
- GNU CC, but only under the conditions described in the
- GNU CC General Public License. A copy of this license is
- supposed to have been given to you along with GNU CC so you
- can know your rights and responsibilities. It should be in a
- file named COPYING. Among other things, the copyright notice
- and this notice must be preserved on all copies. */
- #include "config.h"
- #include "tree.h"
- #include "symseg.h"
- #include "rtl.h"
- #include <stdio.h>
- #include <stab.h>
- /* 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;
- /* 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;
- struct typevec_elt
- {
- int address;
- struct typevec_elt *next;
- };
- static struct typevec_elt *typevec;
- static int total_types;
- struct blockvec_elt
- {
- int address;
- struct blockvec_elt *next;
- };
- static struct blockvec_elt *blockvec;
- 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. */
- void
- symout_init (filename, asm_file, sourcename)
- char *filename;
- FILE *asm_file;
- char *sourcename;
- {
- struct symbol_root buffer;
- 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");
- fprintf (asmfile, ".lcomm Lbss,0\n");
- 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)
- {
- perror (symfile);
- fatal ("Cannot continue compilation.");
- }
- typevec = 0;
- blockvec = 0;
- total_types = 0;
- total_blocks = 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);
- }
- /* Similar 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++;
- }
- }
- /* Similar but only update next_address; do not output anything. */
- 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;
- struct field fieldbuf;
- for (next = types, n_types = 0;
- next;
- next = TREE_CHAIN (next), n_types++);
- records = (struct typerec *) alloca (n_types * sizeof (struct typerec));
- 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;
- }
- 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 = ! integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (next)));
- 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);
- }
- 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);
- 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)
- && type_unsigned_p (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);
- 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);
- }
- }
- 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;
- }
- }
- }
- /* 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 = type_unsigned_p (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)
- return integer_zerop (TYPE_MIN_VALUE (type))
- && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))
- == (1 << TYPE_PRECISION (type)) - 1);
- 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)
- ? TYPE_PRECISION (TREE_TYPE (field))
- : 0);
- buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TREE_TYPE (field));
- buffer.name = (char *) next_address;
- symout_strings_skip (0, IDENTIFIER_LENGTH (DECL_NAME (field)), 0, 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;
- {
- struct field buffer;
- register tree field;
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (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;
- {
- struct field buffer;
- register tree value;
- for (value = TYPE_VALUES (type); value; value = TREE_CHAIN (value))
- symout_strings_print (IDENTIFIER_POINTER (DECL_NAME (value)),
- IDENTIFIER_LENGTH (DECL_NAME (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 int
- 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 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;
- 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 _%s,%d\n", str,
- 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;
- }
- /* 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 int
- 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);
- 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;
- {
- register tree decl;
- 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:
- address =
- symout_block (STMT_VARS (stmt), STMT_TYPE_TAGS (stmt), args,
- superblock_address);
- symout_function (STMT_BODY (stmt), 0, address);
- }
- stmt = TREE_CHAIN (stmt);
- }
- return address;
- }
- /* 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. */
- int
- 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);
- }
- /* 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 *) alloca ((total_types + 1) * sizeof (int));
- int now = time ();
- register int i;
- struct symbol_root buffer;
- char dir[MAXNAMLEN];
- 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.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;
- getwd (dir);
- symout_strings (dir, 0, 0, 0);
- fflush (symfile);
- buffer.length = next_address;
- lseek (fileno (symfile), 0, 0);
- write (fileno (symfile), &buffer, sizeof buffer);
- close (fileno (symfile));
- }
|