/* DWARF debugging format support for GDB.
- Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996
+ Free Software Foundation, Inc.
Written by Fred Fish at Cygnus Support. Portions based on dbxread.c,
mipsread.c, coffread.c, and dwarfread.c from a Data General SVR4 gdb port.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*
#include "complaints.h"
#include <fcntl.h>
-#include <string.h>
-
-#ifndef NO_SYS_FILE
-#include <sys/file.h>
-#endif
-
-/* FIXME -- convert this to SEEK_SET a la POSIX, move to config files. */
-#ifndef L_SET
-#define L_SET 0
-#endif
+#include "gdb_string.h"
/* Some macros to provide DIE info for complaints. */
"DIE @ 0x%x \"%s\", array not row major; not handled correctly", 0, 0
};
+struct complaint missing_at_name =
+{
+ "DIE @ 0x%x, AT_name tag missing", 0, 0
+};
+
typedef unsigned int DIE_REF; /* Reference to a DIE */
#ifndef GCC_PRODUCER
unsigned int has_at_stmt_list:1;
unsigned int has_at_byte_size:1;
unsigned int short_element_list:1;
+
+ /* Kludge to identify register variables */
+
+ unsigned int isreg;
+
+ /* Kludge to identify optimized out variables */
+
+ unsigned int optimized_out;
+
+ /* Kludge to identify basereg references.
+ Nonzero if we have an offset relative to a basereg. */
+
+ unsigned int offreg;
+
+ /* Kludge to identify which base register is it relative to. */
+
+ unsigned int basereg;
};
static int diecount; /* Approximate count of dies for compilation unit */
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 */
-/* 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,
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
- sym_read function to use when expanding a partial symbol table entry
- to a full symbol table entry. */
+/* We put a pointer to this structure in the read_symtab_private field
+ of the psymtab. */
struct dwfinfo {
/* Always the absolute file offset to the start of the ".debug"
/* Forward declarations of static functions so we don't have to worry
about ordering within this file. */
+static void
+free_utypes PARAMS ((PTR));
+
static int
attribute_size PARAMS ((unsigned int));
struct type *));
static int
-locval PARAMS ((char *));
+locval PARAMS ((struct dieinfo *));
static void
set_cu_language PARAMS ((struct dieinfo *));
dbsize = dbfsize;
dbbase = xmalloc (dbsize);
dbroff = 0;
- if ((bfd_seek (abfd, dbfoff, L_SET) != 0) ||
+ if ((bfd_seek (abfd, dbfoff, SEEK_SET) != 0) ||
(bfd_read (dbbase, dbsize, 1, abfd) != dbsize))
{
free (dbbase);
return (utypep);
}
+/*
+
+LOCAL FUNCTION
+
+ free_utypes -- free the utypes array and reset pointer & count
+
+SYNOPSIS
+
+ static void free_utypes (PTR dummy)
+
+DESCRIPTION
+
+ Called via do_cleanups to free the utypes array, reset the pointer to NULL,
+ and set numutypes back to zero. This ensures that the utypes does not get
+ referenced after being freed.
+ */
+
+static void
+free_utypes (dummy)
+ PTR dummy;
+{
+ free (utypes);
+ utypes = NULL;
+ numutypes = 0;
+}
+
+
/*
LOCAL FUNCTION
}
else
{
- type = dwarf_fundamental_type (current_objfile, FT_INTEGER);
+ type = dwarf_fundamental_type (current_objfile, FT_VOID);
}
return (type);
}
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);
+ FIELD_TYPE (list->field) = decode_die_type (&mbr);
+ FIELD_BITPOS (list->field) = 8 * locval (&mbr);
/* Handle bit fields. */
- list -> field.bitsize = mbr.at_bit_size;
+ FIELD_BITSIZE (list->field) = mbr.at_bit_size;
if (BITS_BIG_ENDIAN)
{
/* For big endian bits, the at_bit_offset gives the
anonymous object to the MSB of the field. We don't
have to do anything special since we don't need to
know the size of the anonymous object. */
- list -> field.bitpos += mbr.at_bit_offset;
+ FIELD_BITPOS (list->field) += mbr.at_bit_offset;
}
else
{
a debug information size optimization. */
anonymous_size = TYPE_LENGTH (list -> field.type);
}
- list -> field.bitpos +=
+ FIELD_BITPOS (list->field) +=
anonymous_size * 8 - mbr.at_bit_offset - mbr.at_bit_size;
}
}
unsigned short blocksz;
struct symbol *sym;
int nbytes;
+ int unsigned_enum = 1;
if ((type = lookup_utype (dip -> die_ref)) == NULL)
{
new = (struct nextfield *) alloca (sizeof (struct nextfield));
new -> next = list;
list = new;
- list -> field.type = NULL;
- list -> field.bitsize = 0;
- list -> field.bitpos =
+ FIELD_TYPE (list->field) = NULL;
+ FIELD_BITSIZE (list->field) = 0;
+ FIELD_BITPOS (list->field) =
target_to_host (scan, TARGET_FT_LONG_SIZE (objfile), GET_SIGNED,
objfile);
scan += TARGET_FT_LONG_SIZE (objfile);
SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
SYMBOL_CLASS (sym) = LOC_CONST;
SYMBOL_TYPE (sym) = type;
- SYMBOL_VALUE (sym) = list -> field.bitpos;
+ SYMBOL_VALUE (sym) = FIELD_BITPOS (list->field);
+ if (SYMBOL_VALUE (sym) < 0)
+ unsigned_enum = 0;
add_symbol_to_list (sym, list_in_scope);
}
/* Now create the vector of fields, and record how big it is. This is
vector. */
if (nfields > 0)
{
+ if (unsigned_enum)
+ TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
TYPE_NFIELDS (type) = nfields;
TYPE_FIELDS (type) = (struct field *)
obstack_alloc (&objfile->symbol_obstack, sizeof (struct field) * nfields);
{
register struct context_stack *new;
+ /* AT_name is absent if the function is described with an
+ AT_abstract_origin tag.
+ Ignore the function description for now to avoid GDB core dumps.
+ FIXME: Add code to handle AT_abstract_origin tags properly. */
+ if (dip -> at_name == NULL)
+ {
+ complain (&missing_at_name, DIE_ID);
+ return;
+ }
+
if (objfile -> ei.entry_point >= dip -> at_low_pc &&
objfile -> ei.entry_point < dip -> at_high_pc)
{
}
numutypes = (enddie - thisdie) / 4;
utypes = (struct type **) xmalloc (numutypes * sizeof (struct type *));
- back_to = make_cleanup (free, utypes);
+ back_to = make_cleanup (free_utypes, NULL);
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);
+ record_debugformat ("DWARF 1");
decode_line_numbers (lnbase);
process_dies (thisdie + dip -> die_length, enddie, objfile);
- symtab = end_symtab (dip -> at_high_pc, 0, 0, objfile, 0);
+ symtab = end_symtab (dip -> at_high_pc, objfile, 0);
if (symtab != NULL)
{
symtab -> language = cu_language;
}
do_cleanups (back_to);
- utypes = NULL;
- numutypes = 0;
}
/*
SYNOPSIS
- static int locval (char *loc)
+ static int locval (struct dieinfo *dip)
DESCRIPTION
Given pointer to a string of bytes that define a location, compute
the location and return the value.
+ A location description containing no atoms indicates that the
+ object is optimized out. The optimized_out flag is set for those,
+ the return value is meaningless.
When computing values involving the current value of the frame pointer,
the value zero is used, which results in a value relative to the frame
pointer, rather than the absolute value. This is what GDB wants
anyway.
- When the result is a register number, the global isreg flag is set,
- otherwise it is cleared. This is a kludge until we figure out a better
+ When the result is a register number, the isreg flag is set, otherwise
+ it is cleared. This is a kludge until we figure out a better
way to handle the problem. Gdb's design does not mesh well with the
DWARF notion of a location computing interpreter, which is a shame
because the flexibility goes unused.
*/
static int
-locval (loc)
- char *loc;
+locval (dip)
+ struct dieinfo *dip;
{
unsigned short nbytes;
unsigned short locsize;
auto long stack[64];
int stacki;
+ char *loc;
char *end;
int loc_atom_code;
int loc_value_size;
+ loc = dip -> at_location;
nbytes = attribute_size (AT_location);
locsize = target_to_host (loc, nbytes, GET_UNSIGNED, current_objfile);
loc += nbytes;
end = loc + locsize;
stacki = 0;
stack[stacki] = 0;
- isreg = 0;
- offreg = 0;
+ dip -> isreg = 0;
+ dip -> offreg = 0;
+ dip -> optimized_out = 1;
loc_value_size = TARGET_FT_LONG_SIZE (current_objfile);
while (loc < end)
{
+ dip -> optimized_out = 0;
loc_atom_code = target_to_host (loc, SIZEOF_LOC_ATOM_CODE, GET_UNSIGNED,
current_objfile);
loc += SIZEOF_LOC_ATOM_CODE;
GET_UNSIGNED,
current_objfile));
loc += loc_value_size;
- isreg = 1;
+ dip -> isreg = 1;
break;
case OP_BASEREG:
/* push value of register (number) */
/* Actually, we compute the value as if register has 0, so the
value ends up being the offset from that register. */
- offreg = 1;
- basereg = target_to_host (loc, loc_value_size, GET_UNSIGNED,
- current_objfile);
+ dip -> offreg = 1;
+ dip -> basereg = target_to_host (loc, loc_value_size, GET_UNSIGNED,
+ current_objfile);
loc += loc_value_size;
stack[++stacki] = 0;
break;
foffset = DBFOFF(pst) + dbroff;
base_section_offsets = pst->section_offsets;
baseaddr = ANOFFSET (pst->section_offsets, 0);
- if (bfd_seek (abfd, foffset, L_SET) ||
+ if (bfd_seek (abfd, foffset, SEEK_SET) ||
(bfd_read (dbbase, dbsize, 1, abfd) != dbsize))
{
free (dbbase);
lnbase = NULL;
if (LNFOFF (pst))
{
- if (bfd_seek (abfd, LNFOFF (pst), L_SET) ||
+ if (bfd_seek (abfd, LNFOFF (pst), SEEK_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), L_SET) ||
+ if (bfd_seek (abfd, LNFOFF (pst), SEEK_SET) ||
(bfd_read (lnbase, lnsize, 1, abfd) != lnsize))
{
free (lnbase);
while (scan < listend)
{
scan += TARGET_FT_LONG_SIZE (objfile);
- ADD_PSYMBOL_TO_LIST (scan, strlen (scan), VAR_NAMESPACE, LOC_CONST,
- objfile -> static_psymbols, 0, cu_language,
+ add_psymbol_to_list (scan, strlen (scan), VAR_NAMESPACE, LOC_CONST,
+ &objfile -> static_psymbols, 0, 0, cu_language,
objfile);
scan += strlen (scan) + 1;
}
switch (dip -> die_tag)
{
case TAG_global_subroutine:
- ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
- VAR_NAMESPACE, LOC_BLOCK,
- objfile -> global_psymbols,
- dip -> at_low_pc, cu_language, objfile);
+ add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_BLOCK,
+ &objfile -> global_psymbols,
+ 0, dip -> at_low_pc, cu_language, objfile);
break;
case TAG_global_variable:
- ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
VAR_NAMESPACE, LOC_STATIC,
- objfile -> global_psymbols,
- 0, cu_language, objfile);
+ &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, cu_language, objfile);
+ add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
+ VAR_NAMESPACE, LOC_BLOCK,
+ &objfile -> static_psymbols,
+ 0, dip -> at_low_pc, cu_language, objfile);
break;
case TAG_local_variable:
- ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
VAR_NAMESPACE, LOC_STATIC,
- objfile -> static_psymbols,
- 0, cu_language, objfile);
+ &objfile -> static_psymbols,
+ 0, 0, cu_language, objfile);
break;
case TAG_typedef:
- ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
VAR_NAMESPACE, LOC_TYPEDEF,
- objfile -> static_psymbols,
- 0, cu_language, objfile);
+ &objfile -> static_psymbols,
+ 0, 0, cu_language, objfile);
break;
case TAG_class_type:
case TAG_structure_type:
/* Do not add opaque aggregate definitions to the psymtab. */
if (!dip -> has_at_byte_size)
break;
- ADD_PSYMBOL_TO_LIST (dip -> at_name, strlen (dip -> at_name),
+ add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
STRUCT_NAMESPACE, LOC_TYPEDEF,
- objfile -> static_psymbols,
- 0, cu_language, objfile);
+ &objfile -> static_psymbols,
+ 0, 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),
+ add_psymbol_to_list (dip -> at_name, strlen (dip -> at_name),
VAR_NAMESPACE, LOC_TYPEDEF,
- objfile -> static_psymbols,
- 0, cu_language, objfile);
+ &objfile -> static_psymbols,
+ 0, 0, cu_language, objfile);
}
break;
}
{
sym = (struct symbol *) obstack_alloc (&objfile -> symbol_obstack,
sizeof (struct symbol));
+ OBJSTAT (objfile, n_syms++);
memset (sym, 0, sizeof (struct symbol));
SYMBOL_NAME (sym) = create_name (dip -> at_name,
&objfile->symbol_obstack);
switch (dip -> die_tag)
{
case TAG_label:
- SYMBOL_VALUE (sym) = dip -> at_low_pc;
+ SYMBOL_VALUE_ADDRESS (sym) = dip -> at_low_pc;
SYMBOL_CLASS (sym) = LOC_LABEL;
break;
case TAG_global_subroutine:
case TAG_subroutine:
- SYMBOL_VALUE (sym) = dip -> at_low_pc;
+ SYMBOL_VALUE_ADDRESS (sym) = dip -> at_low_pc;
SYMBOL_TYPE (sym) = lookup_function_type (SYMBOL_TYPE (sym));
+ if (dip -> at_prototyped)
+ TYPE_FLAGS (SYMBOL_TYPE (sym)) |= TYPE_FLAG_PROTOTYPED;
SYMBOL_CLASS (sym) = LOC_BLOCK;
if (dip -> die_tag == TAG_global_subroutine)
{
case TAG_global_variable:
if (dip -> at_location != NULL)
{
- SYMBOL_VALUE (sym) = locval (dip -> at_location);
+ SYMBOL_VALUE_ADDRESS (sym) = locval (dip);
add_symbol_to_list (sym, &global_symbols);
SYMBOL_CLASS (sym) = LOC_STATIC;
SYMBOL_VALUE (sym) += baseaddr;
case TAG_local_variable:
if (dip -> at_location != NULL)
{
- SYMBOL_VALUE (sym) = locval (dip -> at_location);
- add_symbol_to_list (sym, list_in_scope);
- if (isreg)
+ int loc = locval (dip);
+ if (dip -> optimized_out)
+ {
+ SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT;
+ }
+ else if (dip -> isreg)
{
SYMBOL_CLASS (sym) = LOC_REGISTER;
}
- else if (offreg)
+ else if (dip -> offreg)
{
SYMBOL_CLASS (sym) = LOC_BASEREG;
- SYMBOL_BASEREG (sym) = basereg;
+ SYMBOL_BASEREG (sym) = dip -> basereg;
}
else
{
SYMBOL_CLASS (sym) = LOC_STATIC;
SYMBOL_VALUE (sym) += baseaddr;
}
+ if (SYMBOL_CLASS (sym) == LOC_STATIC)
+ {
+ /* LOC_STATIC address class MUST use SYMBOL_VALUE_ADDRESS,
+ which may store to a bigger location than SYMBOL_VALUE. */
+ SYMBOL_VALUE_ADDRESS (sym) = loc;
+ }
+ else
+ {
+ SYMBOL_VALUE (sym) = loc;
+ }
+ add_symbol_to_list (sym, list_in_scope);
}
break;
case TAG_formal_parameter:
if (dip -> at_location != NULL)
{
- SYMBOL_VALUE (sym) = locval (dip -> at_location);
+ SYMBOL_VALUE (sym) = locval (dip);
}
add_symbol_to_list (sym, list_in_scope);
- if (isreg)
+ if (dip -> isreg)
{
SYMBOL_CLASS (sym) = LOC_REGPARM;
}
- else if (offreg)
+ else if (dip -> offreg)
{
SYMBOL_CLASS (sym) = LOC_BASEREG_ARG;
- SYMBOL_BASEREG (sym) = basereg;
+ SYMBOL_BASEREG (sym) = dip -> basereg;
}
else
{
{
sym = (struct symbol *)
obstack_alloc (&objfile -> symbol_obstack, sizeof (struct symbol));
+ OBJSTAT (objfile, n_syms++);
memset (sym, 0, sizeof (struct symbol));
SYMBOL_NAME (sym) = create_name (dip -> at_name,
&objfile->symbol_obstack);