/*
-FIXME: Figure out how to get the frame pointer register number in the
-execution environment of the target. Remove R_FP kludge
-
-FIXME: Add generation of dependencies list to partial symtab code.
+FIXME: Do we need to generate dependencies in partial symtabs?
+(Perhaps we don't need to).
FIXME: Resolve minor differences between what information we put in the
partial symbol table and what dbxread puts in. For example, we don't yet
*/
#include "defs.h"
-#include <varargs.h>
-#include <fcntl.h>
-#include <string.h>
-
#include "bfd.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "symfile.h"
#include "objfiles.h"
+#include <time.h> /* For time_t in libbfd.h. */
+#include <sys/types.h> /* For time_t, if not in time.h. */
#include "libbfd.h" /* FIXME Secret Internal BFD stuff (bfd_read) */
#include "elf/dwarf.h"
#include "buildsym.h"
+#include "demangle.h"
+#include "expression.h" /* Needed for enum exp_opcode in language.h, sigh... */
+#include "language.h"
+#include "complaints.h"
-#ifdef MAINTENANCE /* Define to 1 to compile in some maintenance stuff */
-#define SQUAWK(stuff) dwarfwarn stuff
-#else
-#define SQUAWK(stuff)
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+
+#ifndef NO_SYS_FILE
+#include <sys/file.h>
#endif
-#ifndef R_FP /* FIXME */
-#define R_FP 14 /* Kludge to get frame pointer register number */
+/* FIXME -- convert this to SEEK_SET a la POSIX, move to config files. */
+#ifndef L_SET
+#define L_SET 0
#endif
+/* Some macros to provide DIE info for complaints. */
+
+#define DIE_ID (curdie!=NULL ? curdie->die_ref : 0)
+#define DIE_NAME (curdie!=NULL && curdie->at_name!=NULL) ? curdie->at_name : ""
+
+/* Complaints that can be issued during DWARF debug info reading. */
+
+struct complaint no_bfd_get_N =
+{
+ "DIE @ 0x%x \"%s\", no bfd support for %d byte data object", 0, 0
+};
+
+struct complaint malformed_die =
+{
+ "DIE @ 0x%x \"%s\", malformed DIE, bad length (%d bytes)", 0, 0
+};
+
+struct complaint bad_die_ref =
+{
+ "DIE @ 0x%x \"%s\", reference to DIE (0x%x) outside compilation unit", 0, 0
+};
+
+struct complaint unknown_attribute_form =
+{
+ "DIE @ 0x%x \"%s\", unknown attribute form (0x%x)", 0, 0
+};
+
+struct complaint unknown_attribute_length =
+{
+ "DIE @ 0x%x \"%s\", unknown attribute length, skipped remaining attributes", 0, 0
+};
+
+struct complaint unexpected_fund_type =
+{
+ "DIE @ 0x%x \"%s\", unexpected fundamental type 0x%x", 0, 0
+};
+
+struct complaint unknown_type_modifier =
+{
+ "DIE @ 0x%x \"%s\", unknown type modifier %u", 0, 0
+};
+
+struct complaint volatile_ignored =
+{
+ "DIE @ 0x%x \"%s\", type modifier 'volatile' ignored", 0, 0
+};
+
+struct complaint const_ignored =
+{
+ "DIE @ 0x%x \"%s\", type modifier 'const' ignored", 0, 0
+};
+
+struct complaint botched_modified_type =
+{
+ "DIE @ 0x%x \"%s\", botched modified type decoding (mtype 0x%x)", 0, 0
+};
+
+struct complaint op_deref2 =
+{
+ "DIE @ 0x%x \"%s\", OP_DEREF2 address 0x%x not handled", 0, 0
+};
+
+struct complaint op_deref4 =
+{
+ "DIE @ 0x%x \"%s\", OP_DEREF4 address 0x%x not handled", 0, 0
+};
+
+struct complaint basereg_not_handled =
+{
+ "DIE @ 0x%x \"%s\", BASEREG %d not handled", 0, 0
+};
+
+struct complaint dup_user_type_allocation =
+{
+ "DIE @ 0x%x \"%s\", internal error: duplicate user type allocation", 0, 0
+};
+
+struct complaint dup_user_type_definition =
+{
+ "DIE @ 0x%x \"%s\", internal error: duplicate user type definition", 0, 0
+};
+
+struct complaint missing_tag =
+{
+ "DIE @ 0x%x \"%s\", missing class, structure, or union tag", 0, 0
+};
+
+struct complaint bad_array_element_type =
+{
+ "DIE @ 0x%x \"%s\", bad array element type attribute 0x%x", 0, 0
+};
+
+struct complaint subscript_data_items =
+{
+ "DIE @ 0x%x \"%s\", can't decode subscript data items", 0, 0
+};
+
+struct complaint unhandled_array_subscript_format =
+{
+ "DIE @ 0x%x \"%s\", array subscript format 0x%x not handled yet", 0, 0
+};
+
+struct complaint unknown_array_subscript_format =
+{
+ "DIE @ 0x%x \"%s\", unknown array subscript format %x", 0, 0
+};
+
+struct complaint not_row_major =
+{
+ "DIE @ 0x%x \"%s\", array not row major; not handled correctly", 0, 0
+};
+
typedef unsigned int DIE_REF; /* Reference to a DIE */
#ifndef GCC_PRODUCER
#define GCC_PRODUCER "GNU C "
#endif
-#define STREQ(a,b) (strcmp(a,b)==0)
-#define STREQN(a,b,n) (strncmp(a,b,n)==0)
+#ifndef GPLUS_PRODUCER
+#define GPLUS_PRODUCER "GNU C++ "
+#endif
+
+#ifndef LCC_PRODUCER
+#define LCC_PRODUCER "NCR C/C++"
+#endif
+
+#ifndef CHILL_PRODUCER
+#define CHILL_PRODUCER "GNU Chill "
+#endif
/* Flags to target_to_host() that tell whether or not the data object is
expected to be signed. Used, for example, when fetching a signed
unsigned long at_member;
unsigned long at_discr;
BLOCK * at_discr_value;
- unsigned short at_visibility;
- unsigned long at_import;
BLOCK * at_string_length;
char * at_comp_dir;
char * at_producer;
- unsigned long at_frame_base;
unsigned long at_start_scope;
unsigned long at_stride_size;
unsigned long at_src_info;
char * at_prototyped;
unsigned int has_at_low_pc:1;
unsigned int has_at_stmt_list:1;
+ unsigned int has_at_byte_size:1;
unsigned int short_element_list:1;
};
static struct dieinfo *curdie; /* For warnings and such */
static char *dbbase; /* Base pointer to dwarf info */
+static int dbsize; /* Size of dwarf info in bytes */
static int dbroff; /* Relative offset from start of .debug section */
static char *lnbase; /* Base pointer to line section */
static int isreg; /* Kludge to identify register variables */
-static int offreg; /* Kludge to identify basereg references */
-
+/* Kludge to identify basereg references. Nonzero if we have an offset
+ relative to a basereg. */
+static int offreg;
+/* Which base register is it relative to? */
+static int basereg;
+
+/* This value is added to each symbol value. FIXME: Generalize to
+ the section_offsets structure used by dbxread (once this is done,
+ pass the appropriate section number to end_symtab). */
static CORE_ADDR baseaddr; /* Add to each symbol value */
+/* The section offsets used in the current psymtab or symtab. FIXME,
+ only used to pass one value (baseaddr) at the moment. */
+static struct section_offsets *base_section_offsets;
+
/* Each partial symbol table entry contains a pointer to private data for the
read_symtab() function to use when expanding a partial symbol table entry
to a full symbol table entry. For DWARF debugging info, this data is
*/
struct dwfinfo {
- int dbfoff; /* Absolute file offset to start of .debug section */
+ file_ptr dbfoff; /* Absolute file offset to start of .debug section */
int dbroff; /* Relative offset from start of .debug section */
int dblength; /* Size of the chunk of DIE's being examined */
- int lnfoff; /* Absolute file offset to line table fragment */
+ file_ptr lnfoff; /* Absolute file offset to line table fragment */
};
#define DBFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbfoff)
we can divide any DIE offset by 4 to obtain a unique index into this fixed
size array. Since each element is a 4 byte pointer, it takes exactly as
much memory to hold this array as to hold the DWARF info for a given
- compilation unit. But it gets freed as soon as we are done with it. */
+ compilation unit. But it gets freed as soon as we are done with it.
+ This has worked well in practice, as a reasonable tradeoff between memory
+ consumption and speed, without having to resort to much more complicated
+ algorithms. */
static struct type **utypes; /* Pointer to array of user type pointers */
static int numutypes; /* Max number of user type pointers */
+/* Maintain an array of referenced fundamental types for the current
+ compilation unit being read. For DWARF version 1, we have to construct
+ the fundamental types on the fly, since no information about the
+ fundamental types is supplied. Each such fundamental type is created by
+ calling a language dependent routine to create the type, and then a
+ pointer to that type is then placed in the array at the index specified
+ by it's FT_<TYPENAME> value. The array has a fixed size set by the
+ FT_NUM_MEMBERS compile time constant, which is the number of predefined
+ fundamental types gdb knows how to construct. */
+
+static struct type *ftypes[FT_NUM_MEMBERS]; /* Fundamental types */
+
+/* Record the language for the compilation unit which is currently being
+ processed. We know it once we have seen the TAG_compile_unit DIE,
+ and we need it while processing the DIE's for that compilation unit.
+ It is eventually saved in the symtab structure, but we don't finalize
+ the symtab struct until we have processed all the DIE's for the
+ compilation unit. We also need to get and save a pointer to the
+ language struct for this language, so we can call the language
+ dependent routines for doing things such as creating fundamental
+ types. */
+
+static enum language cu_language;
+static const struct language_defn *cu_language_defn;
+
/* Forward declarations of static functions so we don't have to worry
about ordering within this file. */
static void
add_enum_psymbol PARAMS ((struct dieinfo *, struct objfile *));
+static void
+handle_producer PARAMS ((char *));
+
static void
read_file_scope PARAMS ((struct dieinfo *, char *, char *, struct objfile *));
read_lexical_block_scope PARAMS ((struct dieinfo *, char *, char *,
struct objfile *));
-static void
-dwarfwarn ();
-
static void
scan_partial_symbols PARAMS ((char *, char *, struct objfile *));
static void
-scan_compilation_units PARAMS ((char *, char *, char *, unsigned int,
- unsigned int, struct objfile *));
+scan_compilation_units PARAMS ((char *, char *, file_ptr,
+ file_ptr, struct objfile *));
static void
add_partial_symbol PARAMS ((struct dieinfo *, struct objfile *));
static void
psymtab_to_symtab_1 PARAMS ((struct partial_symtab *));
-static struct symtab *
+static void
read_ofile_symtab PARAMS ((struct partial_symtab *));
static void
decode_array_element_type PARAMS ((char *));
static struct type *
-decode_subscr_data PARAMS ((char *, char *));
+decode_subscript_data_item PARAMS ((char *, char *));
static void
dwarf_read_array_type PARAMS ((struct dieinfo *));
static void
read_tag_pointer_type PARAMS ((struct dieinfo *dip));
+static void
+read_tag_string_type PARAMS ((struct dieinfo *dip));
+
static void
read_subroutine_type PARAMS ((struct dieinfo *, char *, char *));
decode_mod_u_d_type PARAMS ((char *));
static struct type *
-decode_modified_type PARAMS ((unsigned char *, unsigned int, int));
+decode_modified_type PARAMS ((char *, unsigned int, int));
static struct type *
decode_fund_type PARAMS ((unsigned int));
static struct symbol *
new_symbol PARAMS ((struct dieinfo *, struct objfile *));
+static void
+synthesize_typedef PARAMS ((struct dieinfo *, struct objfile *,
+ struct type *));
+
static int
locval PARAMS ((char *));
static void
-record_minimal_symbol PARAMS ((char *, CORE_ADDR, enum minimal_symbol_type,
- struct objfile *));
+set_cu_language PARAMS ((struct dieinfo *));
+
+static struct type *
+dwarf_fundamental_type PARAMS ((struct objfile *, int));
+
+
+/*
+
+LOCAL FUNCTION
+
+ dwarf_fundamental_type -- lookup or create a fundamental type
+
+SYNOPSIS
+
+ struct type *
+ dwarf_fundamental_type (struct objfile *objfile, int typeid)
+
+DESCRIPTION
+
+ DWARF version 1 doesn't supply any fundamental type information,
+ so gdb has to construct such types. It has a fixed number of
+ fundamental types that it knows how to construct, which is the
+ union of all types that it knows how to construct for all languages
+ that it knows about. These are enumerated in gdbtypes.h.
+
+ As an example, assume we find a DIE that references a DWARF
+ fundamental type of FT_integer. We first look in the ftypes
+ array to see if we already have such a type, indexed by the
+ gdb internal value of FT_INTEGER. If so, we simply return a
+ pointer to that type. If not, then we ask an appropriate
+ language dependent routine to create a type FT_INTEGER, using
+ defaults reasonable for the current target machine, and install
+ that type in ftypes for future reference.
+
+RETURNS
+
+ Pointer to a fundamental type.
+
+*/
+
+static struct type *
+dwarf_fundamental_type (objfile, typeid)
+ struct objfile *objfile;
+ int typeid;
+{
+ if (typeid < 0 || typeid >= FT_NUM_MEMBERS)
+ {
+ error ("internal error - invalid fundamental type id %d", typeid);
+ }
+
+ /* Look for this particular type in the fundamental type vector. If one is
+ not found, create and install one appropriate for the current language
+ and the current target machine. */
+
+ if (ftypes[typeid] == NULL)
+ {
+ ftypes[typeid] = cu_language_defn -> la_fund_type(objfile, typeid);
+ }
+
+ return (ftypes[typeid]);
+}
+
+/*
+
+LOCAL FUNCTION
+
+ set_cu_language -- set local copy of language for compilation unit
+
+SYNOPSIS
+
+ void
+ set_cu_language (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Decode the language attribute for a compilation unit DIE and
+ remember what the language was. We use this at various times
+ when processing DIE's for a given compilation unit.
+
+RETURNS
+
+ No return value.
+
+ */
+
+static void
+set_cu_language (dip)
+ struct dieinfo *dip;
+{
+ switch (dip -> at_language)
+ {
+ case LANG_C89:
+ case LANG_C:
+ cu_language = language_c;
+ break;
+ case LANG_C_PLUS_PLUS:
+ cu_language = language_cplus;
+ break;
+ case LANG_CHILL:
+ cu_language = language_chill;
+ break;
+ case LANG_MODULA2:
+ cu_language = language_m2;
+ break;
+ case LANG_ADA83:
+ case LANG_COBOL74:
+ case LANG_COBOL85:
+ case LANG_FORTRAN77:
+ case LANG_FORTRAN90:
+ case LANG_PASCAL83:
+ /* We don't know anything special about these yet. */
+ cu_language = language_unknown;
+ break;
+ default:
+ /* If no at_language, try to deduce one from the filename */
+ cu_language = deduce_language_from_filename (dip -> at_name);
+ break;
+ }
+ cu_language_defn = language_def (cu_language);
+}
/*
SYNOPSIS
- void dwarf_build_psymtabs (int desc, char *filename, CORE_ADDR addr,
- int mainline, unsigned int dbfoff, unsigned int dbsize,
- unsigned int lnoffset, unsigned int lnsize,
- struct objfile *objfile)
+ void dwarf_build_psymtabs (struct objfile *objfile,
+ struct section_offsets *section_offsets,
+ int mainline, file_ptr dbfoff, unsigned int dbfsize,
+ file_ptr lnoffset, unsigned int lnsize)
DESCRIPTION
This function is called upon to build partial symtabs from files
containing DIE's (Dwarf Information Entries) and DWARF line numbers.
- It is passed a file descriptor for an open file containing the DIES
+ It is passed a bfd* containing the DIES
and line number information, the corresponding filename for that
file, a base address for relocating the symbols, a flag indicating
whether or not this debugging information is from a "main symbol
*/
void
-dwarf_build_psymtabs (desc, filename, addr, mainline, dbfoff, dbsize,
- lnoffset, lnsize, objfile)
- int desc;
- char *filename;
- CORE_ADDR addr;
+dwarf_build_psymtabs (objfile, section_offsets, mainline, dbfoff, dbfsize,
+ lnoffset, lnsize)
+ struct objfile *objfile;
+ struct section_offsets *section_offsets;
int mainline;
- unsigned int dbfoff;
- unsigned int dbsize;
- unsigned int lnoffset;
+ file_ptr dbfoff;
+ unsigned int dbfsize;
+ file_ptr lnoffset;
unsigned int lnsize;
- struct objfile *objfile;
{
+ bfd *abfd = objfile->obfd;
struct cleanup *back_to;
current_objfile = objfile;
+ dbsize = dbfsize;
dbbase = xmalloc (dbsize);
dbroff = 0;
- if ((lseek (desc, dbfoff, 0) != dbfoff) ||
- (read (desc, dbbase, dbsize) != dbsize))
+ if ((bfd_seek (abfd, dbfoff, L_SET) != 0) ||
+ (bfd_read (dbbase, dbsize, 1, abfd) != dbsize))
{
free (dbbase);
- error ("can't read DWARF data from '%s'", filename);
+ error ("can't read DWARF data from '%s'", bfd_get_filename (abfd));
}
back_to = make_cleanup (free, dbbase);
/* Save the relocation factor where everybody can see it. */
- baseaddr = addr;
+ base_section_offsets = section_offsets;
+ baseaddr = ANOFFSET (section_offsets, 0);
/* Follow the compilation unit sibling chain, building a partial symbol
table entry for each one. Save enough information about each compilation
unit to locate the full DWARF information later. */
- scan_compilation_units (filename, dbbase, dbbase + dbsize,
- dbfoff, lnoffset, objfile);
+ scan_compilation_units (dbbase, dbbase + dbsize, dbfoff, lnoffset, objfile);
do_cleanups (back_to);
current_objfile = NULL;
}
-
-/*
-
-LOCAL FUNCTION
-
- record_minimal_symbol -- add entry to gdb's minimal symbol table
-
-SYNOPSIS
-
- static void record_minimal_symbol (char *name, CORE_ADDR address,
- enum minimal_symbol_type ms_type,
- struct objfile *objfile)
-
-DESCRIPTION
-
- Given a pointer to the name of a symbol that should be added to the
- minimal symbol table, and the address associated with that
- symbol, records this information for later use in building the
- minimal symbol table.
-
- */
-
-static void
-record_minimal_symbol (name, address, ms_type, objfile)
- char *name;
- CORE_ADDR address;
- enum minimal_symbol_type ms_type;
- struct objfile *objfile;
-{
- name = obsavestring (name, strlen (name), &objfile -> symbol_obstack);
- prim_record_minimal_symbol (name, address, ms_type);
-}
-
-/*
-
-LOCAL FUNCTION
-
- dwarfwarn -- issue a DWARF related warning
-
-DESCRIPTION
-
- Issue warnings about DWARF related things that aren't serious enough
- to warrant aborting with an error, but should not be ignored either.
- This includes things like detectable corruption in DIE's, missing
- DIE's, unimplemented features, etc.
-
- In general, running across tags or attributes that we don't recognize
- is not considered to be a problem and we should not issue warnings
- about such.
-
-NOTES
-
- We mostly follow the example of the error() routine, but without
- returning to command level. It is arguable about whether warnings
- should be issued at all, and if so, where they should go (stdout or
- stderr).
-
- We assume that curdie is valid and contains at least the basic
- information for the DIE where the problem was noticed.
-*/
-
-static void
-dwarfwarn (va_alist)
- va_dcl
-{
- va_list ap;
- char *fmt;
-
- va_start (ap);
- fmt = va_arg (ap, char *);
- warning_setup ();
- fprintf (stderr, "warning: DWARF ref 0x%x: ", curdie -> die_ref);
- if (curdie -> at_name)
- {
- fprintf (stderr, "'%s': ", curdie -> at_name);
- }
- vfprintf (stderr, fmt, ap);
- fprintf (stderr, "\n");
- fflush (stderr);
- va_end (ap);
-}
-
/*
LOCAL FUNCTION
{
register struct context_stack *new;
- (void) push_context (0, dip -> at_low_pc);
+ push_context (0, dip -> at_low_pc);
process_dies (thisdie + dip -> die_length, enddie, objfile);
new = pop_context ();
if (local_symbols != NULL)
utypeidx = (die_ref - dbroff) / 4;
if ((utypeidx < 0) || (utypeidx >= numutypes))
{
- dwarfwarn ("reference to DIE (0x%x) outside compilation unit", die_ref);
+ complain (&bad_die_ref, DIE_ID, DIE_NAME);
}
else
{
typep = utypes + utypeidx;
if ((utypeidx < 0) || (utypeidx >= numutypes))
{
- utypep = lookup_fundamental_type (current_objfile, FT_INTEGER);
- dwarfwarn ("reference to DIE (0x%x) outside compilation unit", die_ref);
+ utypep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ complain (&bad_die_ref, DIE_ID, DIE_NAME);
}
else if (*typep != NULL)
{
utypep = *typep;
- SQUAWK (("internal error: dup user type allocation"));
+ complain (&dup_user_type_allocation, DIE_ID, DIE_NAME);
}
else
{
if (utypep == NULL)
{
- utypep = (struct type *)
- obstack_alloc (¤t_objfile -> type_obstack,
- sizeof (struct type));
- (void) memset (utypep, 0, sizeof (struct type));
- TYPE_OBJFILE (utypep) = current_objfile;
+ utypep = alloc_type (current_objfile);
}
*typep = utypep;
}
}
else
{
- type = lookup_fundamental_type (current_objfile, FT_INTEGER);
+ type = dwarf_fundamental_type (current_objfile, FT_INTEGER);
}
return (type);
}
struct nextfield *new;
int nfields = 0;
int n;
- char *tpart1;
struct dieinfo mbr;
char *nextdie;
+#if !BITS_BIG_ENDIAN
+ int anonymous_size;
+#endif
if ((type = lookup_utype (dip -> die_ref)) == NULL)
{
INIT_CPLUS_SPECIFIC(type);
switch (dip -> die_tag)
{
+ case TAG_class_type:
+ TYPE_CODE (type) = TYPE_CODE_CLASS;
+ break;
case TAG_structure_type:
TYPE_CODE (type) = TYPE_CODE_STRUCT;
- tpart1 = "struct";
break;
case TAG_union_type:
TYPE_CODE (type) = TYPE_CODE_UNION;
- tpart1 = "union";
break;
default:
/* Should never happen */
TYPE_CODE (type) = TYPE_CODE_UNDEF;
- tpart1 = "???";
- SQUAWK (("missing structure or union tag"));
+ complain (&missing_tag, DIE_ID, DIE_NAME);
break;
}
/* Some compilers try to be helpful by inventing "fake" names for
&& *dip -> at_name != '~'
&& *dip -> at_name != '.')
{
- TYPE_NAME (type) = obconcat (&objfile -> type_obstack,
- tpart1, " ", dip -> at_name);
- }
- if (dip -> at_byte_size != 0)
- {
- TYPE_LENGTH (type) = dip -> at_byte_size;
+ TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack,
+ "", "", dip -> at_name);
}
+ /* Use whatever size is known. Zero is a valid size. We might however
+ wish to check has_at_byte_size to make sure that some byte size was
+ given explicitly, but DWARF doesn't specify that explicit sizes of
+ zero have to present, so complaining about missing sizes should
+ probably not be the default. */
+ TYPE_LENGTH (type) = dip -> at_byte_size;
thisdie += dip -> die_length;
while (thisdie < enddie)
{
new -> next = list;
list = new;
/* Save the data. */
- list -> field.name = savestring (mbr.at_name, strlen (mbr.at_name));
+ list -> field.name =
+ obsavestring (mbr.at_name, strlen (mbr.at_name),
+ &objfile -> type_obstack);
list -> field.type = decode_die_type (&mbr);
list -> field.bitpos = 8 * locval (mbr.at_location);
/* Handle bit fields. */
itself. The result is the bit offset of the LSB of the field. */
if (mbr.at_bit_size > 0)
{
+ if (mbr.has_at_byte_size)
+ {
+ /* The size of the anonymous object containing the bit field
+ is explicit, so use the indicated size (in bytes). */
+ anonymous_size = mbr.at_byte_size;
+ }
+ else
+ {
+ /* The size of the anonymous object containing the bit field
+ matches the size of an object of the bit field's type.
+ DWARF allows at_byte_size to be left out in such cases,
+ as a debug information size optimization. */
+ anonymous_size = TYPE_LENGTH (list -> field.type);
+ }
list -> field.bitpos +=
- mbr.at_byte_size * 8 - mbr.at_bit_offset - mbr.at_bit_size;
+ anonymous_size * 8 - mbr.at_bit_offset - mbr.at_bit_size;
}
#endif
nfields++;
{
TYPE_NFIELDS (type) = nfields;
TYPE_FIELDS (type) = (struct field *)
- obstack_alloc (&objfile -> type_obstack,
- sizeof (struct field) * nfields);
+ TYPE_ALLOC (type, sizeof (struct field) * nfields);
/* Copy the saved-up fields into the field vector. */
for (n = nfields; list; list = list -> next)
{
type = struct_type (dip, thisdie, enddie, objfile);
if (!(TYPE_FLAGS (type) & TYPE_FLAG_STUB))
{
- if ((sym = new_symbol (dip, objfile)) != NULL)
+ sym = new_symbol (dip, objfile);
+ if (sym != NULL)
{
SYMBOL_TYPE (sym) = type;
+ if (cu_language == language_cplus)
+ {
+ synthesize_typedef (dip, objfile, type);
+ }
}
}
}
scan += SIZEOF_ATTRIBUTE;
if ((nbytes = attribute_size (attribute)) == -1)
{
- SQUAWK (("bad array element type attribute 0x%x", attribute));
- typep = lookup_fundamental_type (current_objfile, FT_INTEGER);
+ complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
}
else
{
typep = decode_mod_u_d_type (scan);
break;
default:
- SQUAWK (("bad array element type attribute 0x%x", attribute));
- typep = lookup_fundamental_type (current_objfile, FT_INTEGER);
+ complain (&bad_array_element_type, DIE_ID, DIE_NAME, attribute);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
break;
}
}
LOCAL FUNCTION
- decode_subscr_data -- decode array subscript and element type data
+ decode_subscript_data_item -- decode array subscript item
SYNOPSIS
- static struct type *decode_subscr_data (char *scan, char *end)
+ static struct type *
+ decode_subscript_data_item (char *scan, char *end)
DESCRIPTION
source (I.E. leftmost dimension first, next to leftmost second,
etc).
+ The data items describing each array dimension consist of four
+ parts: (1) a format specifier, (2) type type of the subscript
+ index, (3) a description of the low bound of the array dimension,
+ and (4) a description of the high bound of the array dimension.
+
+ The last data item is the description of the type of each of
+ the array elements.
+
We are passed a pointer to the start of the block of bytes
- containing the data items, and a pointer to the first byte past
- the data. This function decodes the data and returns a type.
+ containing the remaining data items, and a pointer to the first
+ byte past the data. This function recursively decodes the
+ remaining data items and returns a type.
+
+ If we somehow fail to decode some data, we complain about it
+ and return a type "array of int".
BUGS
FIXME: This code only implements the forms currently used
*/
static struct type *
-decode_subscr_data (scan, end)
+decode_subscript_data_item (scan, end)
char *scan;
char *end;
{
- struct type *typep = NULL;
- struct type *nexttype;
+ struct type *typep = NULL; /* Array type we are building */
+ struct type *nexttype; /* Type of each element (may be array) */
+ struct type *indextype; /* Type of this index */
+ struct type *rangetype;
unsigned int format;
unsigned short fundtype;
unsigned long lowbound;
case FMT_FT_C_C:
fundtype = target_to_host (scan, SIZEOF_FMT_FT, GET_UNSIGNED,
current_objfile);
+ indextype = decode_fund_type (fundtype);
scan += SIZEOF_FMT_FT;
- if (fundtype != FT_integer && fundtype != FT_signed_integer
- && fundtype != FT_unsigned_integer)
- {
- SQUAWK (("array subscripts must be integral types, not type 0x%x",
- fundtype));
- }
- else
+ nbytes = TARGET_FT_LONG_SIZE (current_objfile);
+ lowbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile);
+ scan += nbytes;
+ highbound = target_to_host (scan, nbytes, GET_UNSIGNED, current_objfile);
+ scan += nbytes;
+ nexttype = decode_subscript_data_item (scan, end);
+ if (nexttype == NULL)
{
- nbytes = TARGET_FT_LONG_SIZE (current_objfile);
- lowbound = target_to_host (scan, nbytes, GET_UNSIGNED,
- current_objfile);
- scan += nbytes;
- highbound = target_to_host (scan, nbytes, GET_UNSIGNED,
- current_objfile);
- scan += nbytes;
- nexttype = decode_subscr_data (scan, end);
- if (nexttype != NULL)
- {
- typep = (struct type *)
- obstack_alloc (¤t_objfile -> type_obstack,
- sizeof (struct type));
- (void) memset (typep, 0, sizeof (struct type));
- TYPE_OBJFILE (typep) = current_objfile;
- TYPE_CODE (typep) = TYPE_CODE_ARRAY;
- TYPE_LENGTH (typep) = TYPE_LENGTH (nexttype);
- TYPE_LENGTH (typep) *= (highbound - lowbound) + 1;
- TYPE_TARGET_TYPE (typep) = nexttype;
- }
+ /* Munged subscript data or other problem, fake it. */
+ complain (&subscript_data_items, DIE_ID, DIE_NAME);
+ nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
}
+ rangetype = create_range_type ((struct type *) NULL, indextype,
+ lowbound, highbound);
+ typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
break;
case FMT_FT_C_X:
case FMT_FT_X_C:
case FMT_UT_C_X:
case FMT_UT_X_C:
case FMT_UT_X_X:
- SQUAWK (("array subscript format 0x%x not handled yet", format));
+ complain (&unhandled_array_subscript_format, DIE_ID, DIE_NAME, format);
+ nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0);
+ typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
break;
default:
- SQUAWK (("unknown array subscript format %x", format));
+ complain (&unknown_array_subscript_format, DIE_ID, DIE_NAME, format);
+ nexttype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ rangetype = create_range_type ((struct type *) NULL, nexttype, 0, 0);
+ typep = create_array_type ((struct type *) NULL, nexttype, rangetype);
break;
}
return (typep);
if (dip -> at_ordering != ORD_row_major)
{
/* FIXME: Can gdb even handle column major arrays? */
- SQUAWK (("array not row major; not handled correctly"));
+ complain (¬_row_major, DIE_ID, DIE_NAME);
}
if ((sub = dip -> at_subscr_data) != NULL)
{
blocksz = target_to_host (sub, nbytes, GET_UNSIGNED, current_objfile);
subend = sub + nbytes + blocksz;
sub += nbytes;
- type = decode_subscr_data (sub, subend);
- if (type == NULL)
+ type = decode_subscript_data_item (sub, subend);
+ if ((utype = lookup_utype (dip -> die_ref)) == NULL)
{
- if ((utype = lookup_utype (dip -> die_ref)) == NULL)
- {
- utype = alloc_utype (dip -> die_ref, NULL);
- }
- TYPE_CODE (utype) = TYPE_CODE_ARRAY;
- TYPE_TARGET_TYPE (utype) =
- lookup_fundamental_type (current_objfile, FT_INTEGER);
- TYPE_LENGTH (utype) = 1 * TYPE_LENGTH (TYPE_TARGET_TYPE (utype));
+ /* Install user defined type that has not been referenced yet. */
+ alloc_utype (dip -> die_ref, type);
+ }
+ else if (TYPE_CODE (utype) == TYPE_CODE_UNDEF)
+ {
+ /* Ick! A forward ref has already generated a blank type in our
+ slot, and this type probably already has things pointing to it
+ (which is what caused it to be created in the first place).
+ If it's just a place holder we can plop our fully defined type
+ on top of it. We can't recover the space allocated for our
+ new type since it might be on an obstack, but we could reuse
+ it if we kept a list of them, but it might not be worth it
+ (FIXME). */
+ *utype = *type;
}
else
{
- if ((utype = lookup_utype (dip -> die_ref)) == NULL)
- {
- (void) alloc_utype (dip -> die_ref, type);
- }
- else
- {
- TYPE_CODE (utype) = TYPE_CODE_ARRAY;
- TYPE_LENGTH (utype) = TYPE_LENGTH (type);
- TYPE_TARGET_TYPE (utype) = TYPE_TARGET_TYPE (type);
- }
+ /* Double ick! Not only is a type already in our slot, but
+ someone has decorated it. Complain and leave it alone. */
+ complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
}
}
}
if ((utype = lookup_utype (dip -> die_ref)) == NULL)
{
utype = lookup_pointer_type (type);
- (void) alloc_utype (dip -> die_ref, utype);
+ alloc_utype (dip -> die_ref, utype);
}
else
{
/*
+LOCAL FUNCTION
+
+ read_tag_string_type -- read TAG_string_type DIE
+
+SYNOPSIS
+
+ static void read_tag_string_type (struct dieinfo *dip)
+
+DESCRIPTION
+
+ Extract all information from a TAG_string_type DIE and add to
+ the user defined type vector. It isn't really a user defined
+ type, but it behaves like one, with other DIE's using an
+ AT_user_def_type attribute to reference it.
+ */
+
+static void
+read_tag_string_type (dip)
+ struct dieinfo *dip;
+{
+ struct type *utype;
+ struct type *indextype;
+ struct type *rangetype;
+ unsigned long lowbound = 0;
+ unsigned long highbound;
+
+ if (dip -> has_at_byte_size)
+ {
+ /* A fixed bounds string */
+ highbound = dip -> at_byte_size - 1;
+ }
+ else
+ {
+ /* A varying length string. Stub for now. (FIXME) */
+ highbound = 1;
+ }
+ indextype = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ rangetype = create_range_type ((struct type *) NULL, indextype, lowbound,
+ highbound);
+
+ utype = lookup_utype (dip -> die_ref);
+ if (utype == NULL)
+ {
+ /* No type defined, go ahead and create a blank one to use. */
+ utype = alloc_utype (dip -> die_ref, (struct type *) NULL);
+ }
+ else
+ {
+ /* Already a type in our slot due to a forward reference. Make sure it
+ is a blank one. If not, complain and leave it alone. */
+ if (TYPE_CODE (utype) != TYPE_CODE_UNDEF)
+ {
+ complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
+ return;
+ }
+ }
+
+ /* Create the string type using the blank type we either found or created. */
+ utype = create_string_type (utype, rangetype);
+}
+
+/*
+
LOCAL FUNCTION
read_subroutine_type -- process TAG_subroutine_type dies
/* This is the first reference to one of these types. Make
a new one and place it in the user defined types. */
ftype = lookup_function_type (type);
- (void) alloc_utype (dip -> die_ref, ftype);
+ alloc_utype (dip -> die_ref, ftype);
}
- else
+ else if (TYPE_CODE (ftype) == TYPE_CODE_UNDEF)
{
/* We have an existing partially constructed type, so bash it
into the correct type. */
TYPE_LENGTH (ftype) = 1;
TYPE_CODE (ftype) = TYPE_CODE_FUNC;
}
+ else
+ {
+ complain (&dup_user_type_definition, DIE_ID, DIE_NAME);
+ }
}
/*
struct symbol *sym;
type = enum_type (dip, objfile);
- if ((sym = new_symbol (dip, objfile)) != NULL)
+ sym = new_symbol (dip, objfile);
+ if (sym != NULL)
{
SYMBOL_TYPE (sym) = type;
+ if (cu_language == language_cplus)
+ {
+ synthesize_typedef (dip, objfile, type);
+ }
}
}
&& *dip -> at_name != '~'
&& *dip -> at_name != '.')
{
- TYPE_NAME (type) = obconcat (&objfile -> type_obstack, "enum",
- " ", dip -> at_name);
+ TYPE_TAG_NAME (type) = obconcat (&objfile -> type_obstack,
+ "", "", dip -> at_name);
}
if (dip -> at_byte_size != 0)
{
target_to_host (scan, TARGET_FT_LONG_SIZE (objfile), GET_SIGNED,
objfile);
scan += TARGET_FT_LONG_SIZE (objfile);
- list -> field.name = savestring (scan, strlen (scan));
+ list -> field.name = obsavestring (scan, strlen (scan),
+ &objfile -> type_obstack);
scan += strlen (scan) + 1;
nfields++;
/* Handcraft a new symbol for this enum member. */
sym = (struct symbol *) obstack_alloc (&objfile->symbol_obstack,
sizeof (struct symbol));
- (void) memset (sym, 0, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
SYMBOL_NAME (sym) = create_name (list -> field.name,
&objfile->symbol_obstack);
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
SYMBOL_CLASS (sym) = LOC_CONST;
SYMBOL_TYPE (sym) = type;
add_symbol_to_list (sym, list_in_scope);
}
/* Now create the vector of fields, and record how big it is. This is
- where we reverse the order, by pulling the members of the list in
+ where we reverse the order, by pulling the members off the list in
reverse order from how they were inserted. If we have no fields
(this is apparently possible in C++) then skip building a field
vector. */
list_in_scope = &file_symbols;
}
+
+/*
+
+LOCAL FUNCTION
+
+ handle_producer -- process the AT_producer attribute
+
+DESCRIPTION
+
+ Perform any operations that depend on finding a particular
+ AT_producer attribute.
+
+ */
+
+static void
+handle_producer (producer)
+ char *producer;
+{
+
+ /* If this compilation unit was compiled with g++ or gcc, then set the
+ processing_gcc_compilation flag. */
+
+ processing_gcc_compilation =
+ STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER))
+ || STREQN (producer, CHILL_PRODUCER, strlen (CHILL_PRODUCER))
+ || STREQN (producer, GCC_PRODUCER, strlen (GCC_PRODUCER));
+
+ /* Select a demangling style if we can identify the producer and if
+ the current style is auto. We leave the current style alone if it
+ is not auto. We also leave the demangling style alone if we find a
+ gcc (cc1) producer, as opposed to a g++ (cc1plus) producer. */
+
+ if (AUTO_DEMANGLING)
+ {
+ if (STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER)))
+ {
+ set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
+ }
+ else if (STREQN (producer, LCC_PRODUCER, strlen (LCC_PRODUCER)))
+ {
+ set_demangling_style (LUCID_DEMANGLING_STYLE_STRING);
+ }
+ }
+}
+
+
/*
LOCAL FUNCTION
objfile -> ei.entry_file_lowpc = dip -> at_low_pc;
objfile -> ei.entry_file_highpc = dip -> at_high_pc;
}
+ set_cu_language (dip);
if (dip -> at_producer != NULL)
{
- processing_gcc_compilation =
- STREQN (dip -> at_producer, GCC_PRODUCER, strlen (GCC_PRODUCER));
+ handle_producer (dip -> at_producer);
}
numutypes = (enddie - thisdie) / 4;
utypes = (struct type **) xmalloc (numutypes * sizeof (struct type *));
back_to = make_cleanup (free, utypes);
- (void) memset (utypes, 0, numutypes * sizeof (struct type *));
- start_symtab (dip -> at_name, NULL, dip -> at_low_pc);
+ memset (utypes, 0, numutypes * sizeof (struct type *));
+ memset (ftypes, 0, FT_NUM_MEMBERS * sizeof (struct type *));
+ start_symtab (dip -> at_name, dip -> at_comp_dir, dip -> at_low_pc);
decode_line_numbers (lnbase);
process_dies (thisdie + dip -> die_length, enddie, objfile);
- symtab = end_symtab (dip -> at_high_pc, 0, 0, objfile);
- /* FIXME: The following may need to be expanded for other languages */
- switch (dip -> at_language)
+
+ symtab = end_symtab (dip -> at_high_pc, 0, 0, objfile, 0);
+ if (symtab != NULL)
{
- case LANG_C89:
- case LANG_C:
- symtab -> language = language_c;
- break;
- case LANG_C_PLUS_PLUS:
- symtab -> language = language_cplus;
- break;
- default:
- ;
- }
+ symtab -> language = cu_language;
+ }
do_cleanups (back_to);
utypes = NULL;
numutypes = 0;
{
nextdie = thisdie + di.die_length;
}
+#ifdef SMASH_TEXT_ADDRESS
+ /* I think that these are always text, not data, addresses. */
+ SMASH_TEXT_ADDRESS (di.at_low_pc);
+ SMASH_TEXT_ADDRESS (di.at_high_pc);
+#endif
switch (di.die_tag)
{
case TAG_compile_unit:
case TAG_lexical_block:
read_lexical_block_scope (&di, thisdie, nextdie, objfile);
break;
+ case TAG_class_type:
case TAG_structure_type:
case TAG_union_type:
read_structure_scope (&di, thisdie, nextdie, objfile);
case TAG_pointer_type:
read_tag_pointer_type (&di);
break;
+ case TAG_string_type:
+ read_tag_string_type (&di);
+ break;
default:
- (void) new_symbol (&di, objfile);
+ new_symbol (&di, objfile);
break;
}
}
auto long stack[64];
int stacki;
char *end;
- long regno;
int loc_atom_code;
int loc_value_size;
break;
case OP_BASEREG:
/* push value of register (number) */
- /* Actually, we compute the value as if register has 0 */
+ /* Actually, we compute the value as if register has 0, so the
+ value ends up being the offset from that register. */
offreg = 1;
- regno = target_to_host (loc, loc_value_size, GET_UNSIGNED,
- current_objfile);
+ basereg = target_to_host (loc, loc_value_size, GET_UNSIGNED,
+ current_objfile);
loc += loc_value_size;
- if (regno == R_FP)
- {
- stack[++stacki] = 0;
- }
- else
- {
- stack[++stacki] = 0;
- SQUAWK (("BASEREG %d not handled!", regno));
- }
+ stack[++stacki] = 0;
break;
case OP_ADDR:
/* push address (relocated address) */
break;
case OP_DEREF2:
/* pop, deref and push 2 bytes (as a long) */
- SQUAWK (("OP_DEREF2 address 0x%x not handled", stack[stacki]));
+ complain (&op_deref2, DIE_ID, DIE_NAME, stack[stacki]);
break;
case OP_DEREF4: /* pop, deref and push 4 bytes (as a long) */
- SQUAWK (("OP_DEREF4 address 0x%x not handled", stack[stacki]));
+ complain (&op_deref4, DIE_ID, DIE_NAME, stack[stacki]);
break;
case OP_ADD: /* pop top 2 items, add, push result */
stack[stacki - 1] += stack[stacki];
SYNOPSIS
- static struct symtab *read_ofile_symtab (struct partial_symtab *pst)
+ static void read_ofile_symtab (struct partial_symtab *pst)
DESCRIPTION
When expanding a partial symbol table entry to a full symbol table
entry, this is the function that gets called to read in the symbols
- for the compilation unit.
-
- Returns a pointer to the newly constructed symtab (which is now
- the new first one on the objfile's symtab list).
+ for the compilation unit. A pointer to the newly constructed symtab,
+ which is now the new first one on the objfile's symtab list, is
+ stashed in the partial symbol table entry.
*/
-static struct symtab *
+static void
read_ofile_symtab (pst)
struct partial_symtab *pst;
{
struct cleanup *back_to;
unsigned long lnsize;
- int foffset;
+ file_ptr foffset;
bfd *abfd;
char lnsizedata[SIZEOF_LINETBL_LENGTH];
unit, seek to the location in the file, and read in all the DIE's. */
diecount = 0;
- dbbase = xmalloc (DBLENGTH(pst));
+ dbsize = DBLENGTH (pst);
+ dbbase = xmalloc (dbsize);
dbroff = DBROFF(pst);
foffset = DBFOFF(pst) + dbroff;
- baseaddr = pst -> addr;
- if (bfd_seek (abfd, foffset, 0) ||
- (bfd_read (dbbase, DBLENGTH(pst), 1, abfd) != DBLENGTH(pst)))
+ base_section_offsets = pst->section_offsets;
+ baseaddr = ANOFFSET (pst->section_offsets, 0);
+ if (bfd_seek (abfd, foffset, L_SET) ||
+ (bfd_read (dbbase, dbsize, 1, abfd) != dbsize))
{
free (dbbase);
error ("can't read DWARF data");
lnbase = NULL;
if (LNFOFF (pst))
{
- if (bfd_seek (abfd, LNFOFF (pst), 0) ||
+ if (bfd_seek (abfd, LNFOFF (pst), L_SET) ||
(bfd_read ((PTR) lnsizedata, sizeof (lnsizedata), 1, abfd) !=
sizeof (lnsizedata)))
{
lnsize = target_to_host (lnsizedata, SIZEOF_LINETBL_LENGTH,
GET_UNSIGNED, pst -> objfile);
lnbase = xmalloc (lnsize);
- if (bfd_seek (abfd, LNFOFF (pst), 0) ||
+ if (bfd_seek (abfd, LNFOFF (pst), L_SET) ||
(bfd_read (lnbase, lnsize, 1, abfd) != lnsize))
{
free (lnbase);
make_cleanup (free, lnbase);
}
- process_dies (dbbase, dbbase + DBLENGTH(pst), pst -> objfile);
+ process_dies (dbbase, dbbase + dbsize, pst -> objfile);
do_cleanups (back_to);
current_objfile = NULL;
- return (pst -> objfile -> symtabs);
+ pst -> symtab = pst -> objfile -> symtabs;
}
/*
struct partial_symtab *pst;
{
int i;
+ struct cleanup *old_chain;
if (pst != NULL)
{
/* Inform about additional files that need to be read in. */
if (info_verbose)
{
- fputs_filtered (" ", stdout);
+ fputs_filtered (" ", gdb_stdout);
wrap_here ("");
- fputs_filtered ("and ", stdout);
+ fputs_filtered ("and ", gdb_stdout);
wrap_here ("");
printf_filtered ("%s...",
pst -> dependencies[i] -> filename);
wrap_here ("");
- fflush (stdout); /* Flush output */
+ gdb_flush (gdb_stdout); /* Flush output */
}
psymtab_to_symtab_1 (pst -> dependencies[i]);
}
}
if (DBLENGTH (pst)) /* Otherwise it's a dummy */
{
- pst -> symtab = read_ofile_symtab (pst);
+ buildsym_init ();
+ old_chain = make_cleanup (really_free_pendings, 0);
+ read_ofile_symtab (pst);
if (info_verbose)
{
printf_filtered ("%d DIE's, sorting...", diecount);
wrap_here ("");
- fflush (stdout);
+ gdb_flush (gdb_stdout);
}
sort_symtab_syms (pst -> symtab);
+ do_cleanups (old_chain);
}
pst -> readin = 1;
}
{
printf_filtered ("Reading in symbols for %s...",
pst -> filename);
- fflush (stdout);
+ gdb_flush (gdb_stdout);
}
psymtab_to_symtab_1 (pst);
if (info_verbose)
{
printf_filtered ("done.\n");
- fflush (stdout);
+ gdb_flush (gdb_stdout);
}
}
}
{
scan += TARGET_FT_LONG_SIZE (objfile);
ADD_PSYMBOL_TO_LIST (scan, strlen (scan), VAR_NAMESPACE, LOC_CONST,
- objfile -> static_psymbols, 0);
+ objfile -> static_psymbols, 0, cu_language,
+ objfile);
scan += strlen (scan) + 1;
}
}
add to a partial symbol table, finish filling in the die info
and then add a partial symbol table entry for it.
+NOTES
+
+ The caller must ensure that the DIE has a valid name attribute.
*/
static void
switch (dip -> die_tag)
{
case TAG_global_subroutine:
- record_minimal_symbol (dip -> at_name, dip -> at_low_pc, mst_text,
- objfile);
ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
VAR_NAMESPACE, LOC_BLOCK,
objfile -> global_psymbols,
- dip -> at_low_pc);
+ dip -> at_low_pc, cu_language, objfile);
break;
case TAG_global_variable:
- record_minimal_symbol (dip -> at_name, locval (dip -> at_location),
- mst_data, objfile);
ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
VAR_NAMESPACE, LOC_STATIC,
objfile -> global_psymbols,
- 0);
+ 0, cu_language, objfile);
break;
case TAG_subroutine:
ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
VAR_NAMESPACE, LOC_BLOCK,
objfile -> static_psymbols,
- dip -> at_low_pc);
+ dip -> at_low_pc, cu_language, objfile);
break;
case TAG_local_variable:
ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
VAR_NAMESPACE, LOC_STATIC,
objfile -> static_psymbols,
- 0);
+ 0, cu_language, objfile);
break;
case TAG_typedef:
ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
VAR_NAMESPACE, LOC_TYPEDEF,
objfile -> static_psymbols,
- 0);
+ 0, cu_language, objfile);
break;
+ case TAG_class_type:
case TAG_structure_type:
case TAG_union_type:
+ case TAG_enumeration_type:
ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
STRUCT_NAMESPACE, LOC_TYPEDEF,
objfile -> static_psymbols,
- 0);
- break;
- case TAG_enumeration_type:
- if (dip -> at_name)
+ 0, cu_language, objfile);
+ if (cu_language == language_cplus)
{
+ /* For C++, these implicitly act as typedefs as well. */
ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
- STRUCT_NAMESPACE, LOC_TYPEDEF,
+ VAR_NAMESPACE, LOC_TYPEDEF,
objfile -> static_psymbols,
- 0);
+ 0, cu_language, objfile);
}
- add_enum_psymbol (dip, objfile);
break;
}
}
Process the DIE's within a single compilation unit, looking for
interesting DIE's that contribute to the partial symbol table entry
- for this compilation unit. Since we cannot follow any sibling
- chains without reading the complete DIE info for every DIE,
- it is probably faster to just sequentially check each one to
- see if it is one of the types we are interested in, and if so,
- then extract all the attributes info and generate a partial
- symbol table entry.
+ for this compilation unit.
NOTES
+ There are some DIE's that may appear both at file scope and within
+ the scope of a function. We are only interested in the ones at file
+ scope, and the only way to tell them apart is to keep track of the
+ scope. For example, consider the test case:
+
+ static int i;
+ main () { int j; }
+
+ for which the relevant DWARF segment has the structure:
+
+ 0x51:
+ 0x23 global subrtn sibling 0x9b
+ name main
+ fund_type FT_integer
+ low_pc 0x800004cc
+ high_pc 0x800004d4
+
+ 0x74:
+ 0x23 local var sibling 0x97
+ name j
+ fund_type FT_integer
+ location OP_BASEREG 0xe
+ OP_CONST 0xfffffffc
+ OP_ADD
+ 0x97:
+ 0x4
+
+ 0x9b:
+ 0x1d local var sibling 0xb8
+ name i
+ fund_type FT_integer
+ location OP_ADDR 0x800025dc
+
+ 0xb8:
+ 0x4
+
+ We want to include the symbol 'i' in the partial symbol table, but
+ not the symbol 'j'. In essence, we want to skip all the dies within
+ the scope of a TAG_global_subroutine DIE.
+
Don't attempt to add anonymous structures or unions since they have
no name. Anonymous enumerations however are processed, because we
want to extract their member names (the check for a tag name is
struct objfile *objfile;
{
char *nextdie;
+ char *temp;
struct dieinfo di;
while (thisdie < enddie)
{
case TAG_global_subroutine:
case TAG_subroutine:
+ completedieinfo (&di, objfile);
+ if (di.at_name && (di.has_at_low_pc || di.at_location))
+ {
+ add_partial_symbol (&di, objfile);
+ /* If there is a sibling attribute, adjust the nextdie
+ pointer to skip the entire scope of the subroutine.
+ Apply some sanity checking to make sure we don't
+ overrun or underrun the range of remaining DIE's */
+ if (di.at_sibling != 0)
+ {
+ temp = dbbase + di.at_sibling - dbroff;
+ if ((temp < thisdie) || (temp >= enddie))
+ {
+ complain (&bad_die_ref, DIE_ID, DIE_NAME,
+ di.at_sibling);
+ }
+ else
+ {
+ nextdie = temp;
+ }
+ }
+ }
+ break;
case TAG_global_variable:
case TAG_local_variable:
completedieinfo (&di, objfile);
}
break;
case TAG_typedef:
+ case TAG_class_type:
case TAG_structure_type:
case TAG_union_type:
completedieinfo (&di, objfile);
break;
case TAG_enumeration_type:
completedieinfo (&di, objfile);
- add_partial_symbol (&di, objfile);
+ if (di.at_name)
+ {
+ add_partial_symbol (&di, objfile);
+ }
+ add_enum_psymbol (&di, objfile);
break;
}
}
*/
static void
-scan_compilation_units (filename, thisdie, enddie, dbfoff, lnoffset, objfile)
- char *filename;
+scan_compilation_units (thisdie, enddie, dbfoff, lnoffset, objfile)
char *thisdie;
char *enddie;
- unsigned int dbfoff;
- unsigned int lnoffset;
+ file_ptr dbfoff;
+ file_ptr lnoffset;
struct objfile *objfile;
{
char *nextdie;
struct partial_symtab *pst;
int culength;
int curoff;
- int curlnoffset;
+ file_ptr curlnoffset;
while (thisdie < enddie)
{
else
{
completedieinfo (&di, objfile);
+ set_cu_language (&di);
if (di.at_sibling != 0)
{
nextdie = dbbase + di.at_sibling - dbroff;
/* First allocate a new partial symbol table structure */
- pst = start_psymtab_common (objfile, baseaddr, di.at_name,
- di.at_low_pc,
+ pst = start_psymtab_common (objfile, base_section_offsets,
+ di.at_name, di.at_low_pc,
objfile -> global_psymbols.next,
objfile -> static_psymbols.next);
{
sym = (struct symbol *) obstack_alloc (&objfile -> symbol_obstack,
sizeof (struct symbol));
- (void) memset (sym, 0, sizeof (struct symbol));
- SYMBOL_NAME (sym) = create_name (dip -> at_name, &objfile->symbol_obstack);
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = create_name (dip -> at_name,
+ &objfile->symbol_obstack);
/* default assumptions */
SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
SYMBOL_CLASS (sym) = LOC_STATIC;
SYMBOL_TYPE (sym) = decode_die_type (dip);
+
+ /* If this symbol is from a C++ compilation, then attempt to cache the
+ demangled form for future reference. This is a typical time versus
+ space tradeoff, that was decided in favor of time because it sped up
+ C++ symbol lookups by a factor of about 20. */
+
+ SYMBOL_LANGUAGE (sym) = cu_language;
+ SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile -> symbol_obstack);
switch (dip -> die_tag)
{
case TAG_label:
}
else if (offreg)
{
- SYMBOL_CLASS (sym) = LOC_LOCAL;
+ SYMBOL_CLASS (sym) = LOC_BASEREG;
+ SYMBOL_BASEREG (sym) = basereg;
}
else
{
{
SYMBOL_CLASS (sym) = LOC_REGPARM;
}
+ else if (offreg)
+ {
+ SYMBOL_CLASS (sym) = LOC_BASEREG_ARG;
+ SYMBOL_BASEREG (sym) = basereg;
+ }
else
{
SYMBOL_CLASS (sym) = LOC_ARG;
/* From varargs functions; gdb doesn't seem to have any interest in
this information, so just ignore it for now. (FIXME?) */
break;
+ case TAG_class_type:
case TAG_structure_type:
case TAG_union_type:
case TAG_enumeration_type:
/*
+LOCAL FUNCTION
+
+ synthesize_typedef -- make a symbol table entry for a "fake" typedef
+
+SYNOPSIS
+
+ static void synthesize_typedef (struct dieinfo *dip,
+ struct objfile *objfile,
+ struct type *type);
+
+DESCRIPTION
+
+ Given a pointer to a DWARF information entry, synthesize a typedef
+ for the name in the DIE, using the specified type.
+
+ This is used for C++ class, structs, unions, and enumerations to
+ set up the tag name as a type.
+
+ */
+
+static void
+synthesize_typedef (dip, objfile, type)
+ struct dieinfo *dip;
+ struct objfile *objfile;
+ struct type *type;
+{
+ struct symbol *sym = NULL;
+
+ if (dip -> at_name != NULL)
+ {
+ sym = (struct symbol *)
+ obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ memset (sym, 0, sizeof (struct symbol));
+ SYMBOL_NAME (sym) = create_name (dip -> at_name,
+ &objfile->symbol_obstack);
+ SYMBOL_INIT_LANGUAGE_SPECIFIC (sym, cu_language);
+ SYMBOL_TYPE (sym) = type;
+ SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
+ add_symbol_to_list (sym, list_in_scope);
+ }
+}
+
+/*
+
LOCAL FUNCTION
decode_mod_fund_type -- decode a modified fundamental type
SYNOPSIS
- static struct type *decode_modified_type (unsigned char *modifiers,
+ static struct type *decode_modified_type (char *modifiers,
unsigned short modcount, int mtype)
DESCRIPTION
static struct type *
decode_modified_type (modifiers, modcount, mtype)
- unsigned char *modifiers;
+ char *modifiers;
unsigned int modcount;
int mtype;
{
struct type *typep = NULL;
unsigned short fundtype;
DIE_REF die_ref;
- unsigned char modifier;
+ char modifier;
int nbytes;
if (modcount == 0)
}
break;
default:
- SQUAWK (("botched modified type decoding (mtype 0x%x)", mtype));
- typep = lookup_fundamental_type (current_objfile, FT_INTEGER);
+ complain (&botched_modified_type, DIE_ID, DIE_NAME, mtype);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
break;
}
}
typep = lookup_reference_type (typep);
break;
case MOD_const:
- SQUAWK (("type modifier 'const' ignored")); /* FIXME */
+ complain (&const_ignored, DIE_ID, DIE_NAME); /* FIXME */
break;
case MOD_volatile:
- SQUAWK (("type modifier 'volatile' ignored")); /* FIXME */
+ complain (&volatile_ignored, DIE_ID, DIE_NAME); /* FIXME */
break;
default:
- if (!(MOD_lo_user <= modifier && modifier <= MOD_hi_user))
+ if (!(MOD_lo_user <= (unsigned char) modifier
+ && (unsigned char) modifier <= MOD_hi_user))
{
- SQUAWK (("unknown type modifier %u", modifier));
+ complain (&unknown_type_modifier, DIE_ID, DIE_NAME, modifier);
}
break;
}
NOTES
- If we encounter a fundamental type that we are unprepared to
- deal with, and it is not in the range of those types defined
- as application specific types, then we issue a warning and
- treat the type as an "int".
+ For robustness, if we are asked to translate a fundamental
+ type that we are unprepared to deal with, we return int so
+ callers can always depend upon a valid type being returned,
+ and so gdb may at least do something reasonable by default.
+ If the type is not in the range of those types defined as
+ application specific types, we also issue a warning.
*/
static struct type *
{
case FT_void:
- typep = lookup_fundamental_type (current_objfile, FT_VOID);
+ typep = dwarf_fundamental_type (current_objfile, FT_VOID);
break;
case FT_boolean: /* Was FT_set in AT&T version */
- typep = lookup_fundamental_type (current_objfile, FT_BOOLEAN);
+ typep = dwarf_fundamental_type (current_objfile, FT_BOOLEAN);
break;
case FT_pointer: /* (void *) */
- typep = lookup_fundamental_type (current_objfile, FT_VOID);
+ typep = dwarf_fundamental_type (current_objfile, FT_VOID);
typep = lookup_pointer_type (typep);
break;
case FT_char:
- typep = lookup_fundamental_type (current_objfile, FT_CHAR);
+ typep = dwarf_fundamental_type (current_objfile, FT_CHAR);
break;
case FT_signed_char:
- typep = lookup_fundamental_type (current_objfile, FT_SIGNED_CHAR);
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_CHAR);
break;
case FT_unsigned_char:
- typep = lookup_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
break;
case FT_short:
- typep = lookup_fundamental_type (current_objfile, FT_SHORT);
+ typep = dwarf_fundamental_type (current_objfile, FT_SHORT);
break;
case FT_signed_short:
- typep = lookup_fundamental_type (current_objfile, FT_SIGNED_SHORT);
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_SHORT);
break;
case FT_unsigned_short:
- typep = lookup_fundamental_type (current_objfile, FT_UNSIGNED_SHORT);
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_SHORT);
break;
case FT_integer:
- typep = lookup_fundamental_type (current_objfile, FT_INTEGER);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
break;
case FT_signed_integer:
- typep = lookup_fundamental_type (current_objfile, FT_SIGNED_INTEGER);
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_INTEGER);
break;
case FT_unsigned_integer:
- typep = lookup_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
break;
case FT_long:
- typep = lookup_fundamental_type (current_objfile, FT_LONG);
+ typep = dwarf_fundamental_type (current_objfile, FT_LONG);
break;
case FT_signed_long:
- typep = lookup_fundamental_type (current_objfile, FT_SIGNED_LONG);
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG);
break;
case FT_unsigned_long:
- typep = lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
break;
case FT_long_long:
- typep = lookup_fundamental_type (current_objfile, FT_LONG_LONG);
+ typep = dwarf_fundamental_type (current_objfile, FT_LONG_LONG);
break;
case FT_signed_long_long:
- typep = lookup_fundamental_type (current_objfile, FT_SIGNED_LONG_LONG);
+ typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG_LONG);
break;
case FT_unsigned_long_long:
- typep = lookup_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG);
+ typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG);
break;
case FT_float:
- typep = lookup_fundamental_type (current_objfile, FT_FLOAT);
+ typep = dwarf_fundamental_type (current_objfile, FT_FLOAT);
break;
case FT_dbl_prec_float:
- typep = lookup_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
+ typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
break;
case FT_ext_prec_float:
- typep = lookup_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT);
+ typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT);
break;
case FT_complex:
- typep = lookup_fundamental_type (current_objfile, FT_COMPLEX);
+ typep = dwarf_fundamental_type (current_objfile, FT_COMPLEX);
break;
case FT_dbl_prec_complex:
- typep = lookup_fundamental_type (current_objfile, FT_DBL_PREC_COMPLEX);
+ typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_COMPLEX);
break;
case FT_ext_prec_complex:
- typep = lookup_fundamental_type (current_objfile, FT_EXT_PREC_COMPLEX);
+ typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_COMPLEX);
break;
}
- if ((typep == NULL) && !(FT_lo_user <= fundtype && fundtype <= FT_hi_user))
+ if (typep == NULL)
{
- SQUAWK (("unexpected fundamental type 0x%x", fundtype));
- typep = lookup_fundamental_type (current_objfile, FT_VOID);
+ typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ if (!(FT_lo_user <= fundtype && fundtype <= FT_hi_user))
+ {
+ complain (&unexpected_fund_type, DIE_ID, DIE_NAME, fundtype);
+ }
}
return (typep);
length = strlen (name) + 1;
newname = (char *) obstack_alloc (obstackp, length);
- (void) strcpy (newname, name);
+ strcpy (newname, name);
return (newname);
}
that if a padding DIE is used for alignment and the amount needed is
less than SIZEOF_DIE_LENGTH, then the padding DIE has to be big
enough to align to the next alignment boundry.
+
+ We do some basic sanity checking here, such as verifying that the
+ length of the die would not cause it to overrun the recorded end of
+ the buffer holding the DIE info. If we find a DIE that is either
+ too small or too large, we force it's length to zero which should
+ cause the caller to take appropriate action.
*/
static void
struct objfile *objfile;
{
curdie = dip;
- (void) memset (dip, 0, sizeof (struct dieinfo));
+ memset (dip, 0, sizeof (struct dieinfo));
dip -> die = diep;
dip -> die_ref = dbroff + (diep - dbbase);
dip -> die_length = target_to_host (diep, SIZEOF_DIE_LENGTH, GET_UNSIGNED,
objfile);
- if (dip -> die_length < SIZEOF_DIE_LENGTH)
+ if ((dip -> die_length < SIZEOF_DIE_LENGTH) ||
+ ((diep + dip -> die_length) > (dbbase + dbsize)))
{
- dwarfwarn ("malformed DIE, bad length (%d bytes)", dip -> die_length);
+ complain (&malformed_die, DIE_ID, DIE_NAME, dip -> die_length);
+ dip -> die_length = 0;
}
else if (dip -> die_length < (SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG))
{
diep += SIZEOF_ATTRIBUTE;
if ((nbytes = attribute_size (attr)) == -1)
{
- SQUAWK (("unknown attribute length, skipped remaining attributes"));;
+ complain (&unknown_attribute_length, DIE_ID, DIE_NAME);
diep = end;
continue;
}
dip -> at_bit_offset = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
- case AT_visibility:
- dip -> at_visibility = target_to_host (diep, nbytes, GET_UNSIGNED,
- objfile);
- break;
case AT_sibling:
dip -> at_sibling = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
case AT_byte_size:
dip -> at_byte_size = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
+ dip -> has_at_byte_size = 1;
break;
case AT_bit_size:
dip -> at_bit_size = target_to_host (diep, nbytes, GET_UNSIGNED,
dip -> at_discr = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
- case AT_import:
- dip -> at_import = target_to_host (diep, nbytes, GET_UNSIGNED,
- objfile);
- break;
case AT_location:
dip -> at_location = diep;
break;
dip -> at_name = diep;
break;
case AT_comp_dir:
- dip -> at_comp_dir = diep;
+ /* For now, ignore any "hostname:" portion, since gdb doesn't
+ know how to deal with it. (FIXME). */
+ dip -> at_comp_dir = strrchr (diep, ':');
+ if (dip -> at_comp_dir != NULL)
+ {
+ dip -> at_comp_dir++;
+ }
+ else
+ {
+ dip -> at_comp_dir = diep;
+ }
break;
case AT_producer:
dip -> at_producer = diep;
break;
- case AT_frame_base:
- dip -> at_frame_base = target_to_host (diep, nbytes, GET_UNSIGNED,
- objfile);
- break;
case AT_start_scope:
dip -> at_start_scope = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
diep += strlen (diep) + 1;
break;
default:
- SQUAWK (("unknown attribute form (0x%x)", form));
- SQUAWK (("unknown attribute length, skipped remaining attributes"));;
+ complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form);
diep = end;
break;
}
rtnval = bfd_get_8 (objfile -> obfd, (bfd_byte *) from);
break;
default:
- dwarfwarn ("no bfd support for %d byte data object", nbytes);
+ complain (&no_bfd_get_N, DIE_ID, DIE_NAME, nbytes);
rtnval = 0;
break;
}
nbytes = TARGET_FT_POINTER_SIZE (objfile);
break;
default:
- SQUAWK (("unknown attribute form (0x%x)", form));
+ complain (&unknown_attribute_form, DIE_ID, DIE_NAME, form);
nbytes = -1;
break;
}