#include "defs.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "symfile.h"
#include "objfiles.h"
#include "elf/dwarf.h"
#include "buildsym.h"
#include "demangle.h"
#include "expression.h"
#include "language.h"
#include "complaints.h"
#include <fcntl.h>
#include "gdb_string.h"
#define DIE_ID (curdie!=NULL ? curdie->die_ref : 0)
#define DIE_NAME (curdie!=NULL && curdie->at_name!=NULL) ? curdie->at_name : ""
static void
bad_die_ref_complaint (int arg1, const char *arg2, int arg3)
{
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", reference to DIE (0x%x) outside compilation unit",
arg1, arg2, arg3);
}
static void
unknown_attribute_form_complaint (int arg1, const char *arg2, int arg3)
{
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", unknown attribute form (0x%x)", arg1, arg2,
arg3);
}
static void
dup_user_type_definition_complaint (int arg1, const char *arg2)
{
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", internal error: duplicate user type definition",
arg1, arg2);
}
static void
bad_array_element_type_complaint (int arg1, const char *arg2, int arg3)
{
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", bad array element type attribute 0x%x", arg1,
arg2, arg3);
}
typedef unsigned int DIE_REF;
#ifndef GCC_PRODUCER
#define GCC_PRODUCER "GNU C "
#endif
#ifndef GPLUS_PRODUCER
#define GPLUS_PRODUCER "GNU C++ "
#endif
#ifndef LCC_PRODUCER
#define LCC_PRODUCER "NCR C/C++"
#endif
#define GET_UNSIGNED 0
#define GET_SIGNED 1
#define SIZEOF_DIE_LENGTH 4
#define SIZEOF_DIE_TAG 2
#define SIZEOF_ATTRIBUTE 2
#define SIZEOF_FORMAT_SPECIFIER 1
#define SIZEOF_FMT_FT 2
#define SIZEOF_LINETBL_LENGTH 4
#define SIZEOF_LINETBL_LINENO 4
#define SIZEOF_LINETBL_STMT 2
#define SIZEOF_LINETBL_DELTA 4
#define SIZEOF_LOC_ATOM_CODE 1
#define FORM_FROM_ATTR(attr) ((attr) & 0xF)
#define TARGET_FT_POINTER_SIZE(objfile) (TARGET_PTR_BIT / TARGET_CHAR_BIT)
#define TARGET_FT_LONG_SIZE(objfile) (TARGET_LONG_BIT / TARGET_CHAR_BIT)
#define AT_short_element_list (0x00f0|FORM_BLOCK2)
typedef char BLOCK;
struct dieinfo
{
char *die;
unsigned long die_length;
DIE_REF die_ref;
unsigned short die_tag;
unsigned long at_padding;
unsigned long at_sibling;
BLOCK *at_location;
char *at_name;
unsigned short at_fund_type;
BLOCK *at_mod_fund_type;
unsigned long at_user_def_type;
BLOCK *at_mod_u_d_type;
unsigned short at_ordering;
BLOCK *at_subscr_data;
unsigned long at_byte_size;
unsigned short at_bit_offset;
unsigned long at_bit_size;
BLOCK *at_element_list;
unsigned long at_stmt_list;
CORE_ADDR at_low_pc;
CORE_ADDR at_high_pc;
unsigned long at_language;
unsigned long at_member;
unsigned long at_discr;
BLOCK *at_discr_value;
BLOCK *at_string_length;
char *at_comp_dir;
char *at_producer;
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;
unsigned int isreg;
unsigned int optimized_out;
unsigned int offreg;
unsigned int basereg;
};
static int diecount;
static struct dieinfo *curdie;
static char *dbbase;
static int dbsize;
static int dbroff;
static char *lnbase;
static CORE_ADDR baseaddr;
static struct section_offsets *base_section_offsets;
struct dwfinfo
{
file_ptr dbfoff;
int dbroff;
int dblength;
file_ptr lnfoff;
};
#define DBFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbfoff)
#define DBROFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->dbroff)
#define DBLENGTH(p) (((struct dwfinfo *)((p)->read_symtab_private))->dblength)
#define LNFOFF(p) (((struct dwfinfo *)((p)->read_symtab_private))->lnfoff)
struct pending **list_in_scope = &file_symbols;
static struct type **utypes;
static int numutypes;
static struct type *ftypes[FT_NUM_MEMBERS];
static enum language cu_language;
static const struct language_defn *cu_language_defn;
static void free_utypes (void *);
static int attribute_size (unsigned int);
static CORE_ADDR target_to_host (char *, int, int, struct objfile *);
static void add_enum_psymbol (struct dieinfo *, struct objfile *);
static void handle_producer (char *);
static void read_file_scope (struct dieinfo *, char *, char *,
struct objfile *);
static void read_func_scope (struct dieinfo *, char *, char *,
struct objfile *);
static void read_lexical_block_scope (struct dieinfo *, char *, char *,
struct objfile *);
static void scan_partial_symbols (char *, char *, struct objfile *);
static void scan_compilation_units (char *, char *, file_ptr, file_ptr,
struct objfile *);
static void add_partial_symbol (struct dieinfo *, struct objfile *);
static void basicdieinfo (struct dieinfo *, char *, struct objfile *);
static void completedieinfo (struct dieinfo *, struct objfile *);
static void dwarf_psymtab_to_symtab (struct partial_symtab *);
static void psymtab_to_symtab_1 (struct partial_symtab *);
static void read_ofile_symtab (struct partial_symtab *);
static void process_dies (char *, char *, struct objfile *);
static void read_structure_scope (struct dieinfo *, char *, char *,
struct objfile *);
static struct type *decode_array_element_type (char *);
static struct type *decode_subscript_data_item (char *, char *);
static void dwarf_read_array_type (struct dieinfo *);
static void read_tag_pointer_type (struct dieinfo *dip);
static void read_tag_string_type (struct dieinfo *dip);
static void read_subroutine_type (struct dieinfo *, char *, char *);
static void read_enumeration (struct dieinfo *, char *, char *,
struct objfile *);
static struct type *struct_type (struct dieinfo *, char *, char *,
struct objfile *);
static struct type *enum_type (struct dieinfo *, struct objfile *);
static void decode_line_numbers (char *);
static struct type *decode_die_type (struct dieinfo *);
static struct type *decode_mod_fund_type (char *);
static struct type *decode_mod_u_d_type (char *);
static struct type *decode_modified_type (char *, unsigned int, int);
static struct type *decode_fund_type (unsigned int);
static char *create_name (char *, struct obstack *);
static struct type *lookup_utype (DIE_REF);
static struct type *alloc_utype (DIE_REF, struct type *);
static struct symbol *new_symbol (struct dieinfo *, struct objfile *);
static void synthesize_typedef (struct dieinfo *, struct objfile *,
struct type *);
static int locval (struct dieinfo *);
static void set_cu_language (struct dieinfo *);
static struct type *dwarf_fundamental_type (struct objfile *, int);
static struct type *
dwarf_fundamental_type (struct objfile *objfile, int typeid)
{
if (typeid < 0 || typeid >= FT_NUM_MEMBERS)
{
error ("internal error - invalid fundamental type id %d", typeid);
}
if (ftypes[typeid] == NULL)
{
ftypes[typeid] = cu_language_defn->la_fund_type (objfile, typeid);
}
return (ftypes[typeid]);
}
static void
set_cu_language (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_MODULA2:
cu_language = language_m2;
break;
case LANG_FORTRAN77:
case LANG_FORTRAN90:
cu_language = language_fortran;
break;
case LANG_ADA83:
case LANG_COBOL74:
case LANG_COBOL85:
case LANG_PASCAL83:
cu_language = language_unknown;
break;
default:
cu_language = deduce_language_from_filename (dip->at_name);
break;
}
cu_language_defn = language_def (cu_language);
}
void
dwarf_build_psymtabs (struct objfile *objfile, int mainline, file_ptr dbfoff,
unsigned int dbfsize, file_ptr lnoffset,
unsigned int lnsize)
{
bfd *abfd = objfile->obfd;
struct cleanup *back_to;
current_objfile = objfile;
dbsize = dbfsize;
dbbase = xmalloc (dbsize);
dbroff = 0;
if ((bfd_seek (abfd, dbfoff, SEEK_SET) != 0) ||
(bfd_bread (dbbase, dbsize, abfd) != dbsize))
{
xfree (dbbase);
error ("can't read DWARF data from '%s'", bfd_get_filename (abfd));
}
back_to = make_cleanup (xfree, dbbase);
if (mainline
|| (objfile->global_psymbols.size == 0
&& objfile->static_psymbols.size == 0))
{
init_psymbol_list (objfile, 1024);
}
base_section_offsets = objfile->section_offsets;
baseaddr = ANOFFSET (objfile->section_offsets, 0);
scan_compilation_units (dbbase, dbbase + dbsize, dbfoff, lnoffset, objfile);
do_cleanups (back_to);
current_objfile = NULL;
}
static void
read_lexical_block_scope (struct dieinfo *dip, char *thisdie, char *enddie,
struct objfile *objfile)
{
register struct context_stack *new;
push_context (0, dip->at_low_pc);
process_dies (thisdie + dip->die_length, enddie, objfile);
new = pop_context ();
if (local_symbols != NULL)
{
finish_block (0, &local_symbols, new->old_blocks, new->start_addr,
dip->at_high_pc, objfile);
}
local_symbols = new->locals;
}
static struct type *
lookup_utype (DIE_REF die_ref)
{
struct type *type = NULL;
int utypeidx;
utypeidx = (die_ref - dbroff) / 4;
if ((utypeidx < 0) || (utypeidx >= numutypes))
{
bad_die_ref_complaint (DIE_ID, DIE_NAME, die_ref);
}
else
{
type = *(utypes + utypeidx);
}
return (type);
}
static struct type *
alloc_utype (DIE_REF die_ref, struct type *utypep)
{
struct type **typep;
int utypeidx;
utypeidx = (die_ref - dbroff) / 4;
typep = utypes + utypeidx;
if ((utypeidx < 0) || (utypeidx >= numutypes))
{
utypep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
bad_die_ref_complaint (DIE_ID, DIE_NAME, die_ref);
}
else if (*typep != NULL)
{
utypep = *typep;
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", internal error: duplicate user type allocation",
DIE_ID, DIE_NAME);
}
else
{
if (utypep == NULL)
{
utypep = alloc_type (current_objfile);
}
*typep = utypep;
}
return (utypep);
}
static void
free_utypes (void *dummy)
{
xfree (utypes);
utypes = NULL;
numutypes = 0;
}
static struct type *
decode_die_type (struct dieinfo *dip)
{
struct type *type = NULL;
if (dip->at_fund_type != 0)
{
type = decode_fund_type (dip->at_fund_type);
}
else if (dip->at_mod_fund_type != NULL)
{
type = decode_mod_fund_type (dip->at_mod_fund_type);
}
else if (dip->at_user_def_type)
{
if ((type = lookup_utype (dip->at_user_def_type)) == NULL)
{
type = alloc_utype (dip->at_user_def_type, NULL);
}
}
else if (dip->at_mod_u_d_type)
{
type = decode_mod_u_d_type (dip->at_mod_u_d_type);
}
else
{
type = dwarf_fundamental_type (current_objfile, FT_VOID);
}
return (type);
}
static struct type *
struct_type (struct dieinfo *dip, char *thisdie, char *enddie,
struct objfile *objfile)
{
struct type *type;
struct nextfield
{
struct nextfield *next;
struct field field;
};
struct nextfield *list = NULL;
struct nextfield *new;
int nfields = 0;
int n;
struct dieinfo mbr;
char *nextdie;
int anonymous_size;
if ((type = lookup_utype (dip->die_ref)) == NULL)
{
type = alloc_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;
break;
case TAG_union_type:
TYPE_CODE (type) = TYPE_CODE_UNION;
break;
default:
TYPE_CODE (type) = TYPE_CODE_UNDEF;
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", missing class, structure, or union tag",
DIE_ID, DIE_NAME);
break;
}
if (dip->at_name != NULL
&& *dip->at_name != '~'
&& *dip->at_name != '.')
{
TYPE_TAG_NAME (type) = obconcat (&objfile->type_obstack,
"", "", dip->at_name);
}
TYPE_LENGTH (type) = dip->at_byte_size;
thisdie += dip->die_length;
while (thisdie < enddie)
{
basicdieinfo (&mbr, thisdie, objfile);
completedieinfo (&mbr, objfile);
if (mbr.die_length <= SIZEOF_DIE_LENGTH)
{
break;
}
else if (mbr.at_sibling != 0)
{
nextdie = dbbase + mbr.at_sibling - dbroff;
}
else
{
nextdie = thisdie + mbr.die_length;
}
switch (mbr.die_tag)
{
case TAG_member:
new = (struct nextfield *) alloca (sizeof (struct nextfield));
new->next = list;
list = new;
list->field.name =
obsavestring (mbr.at_name, strlen (mbr.at_name),
&objfile->type_obstack);
FIELD_TYPE (list->field) = decode_die_type (&mbr);
FIELD_BITPOS (list->field) = 8 * locval (&mbr);
FIELD_STATIC_KIND (list->field) = 0;
FIELD_BITSIZE (list->field) = mbr.at_bit_size;
if (BITS_BIG_ENDIAN)
{
FIELD_BITPOS (list->field) += mbr.at_bit_offset;
}
else
{
if (mbr.at_bit_size > 0)
{
if (mbr.has_at_byte_size)
{
anonymous_size = mbr.at_byte_size;
}
else
{
anonymous_size = TYPE_LENGTH (list->field.type);
}
FIELD_BITPOS (list->field) +=
anonymous_size * 8 - mbr.at_bit_offset - mbr.at_bit_size;
}
}
nfields++;
break;
default:
process_dies (thisdie, nextdie, objfile);
break;
}
thisdie = nextdie;
}
if (nfields == 0)
{
TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
}
else
{
TYPE_NFIELDS (type) = nfields;
TYPE_FIELDS (type) = (struct field *)
TYPE_ALLOC (type, sizeof (struct field) * nfields);
for (n = nfields; list; list = list->next)
{
TYPE_FIELD (type, --n) = list->field;
}
}
return (type);
}
static void
read_structure_scope (struct dieinfo *dip, char *thisdie, char *enddie,
struct objfile *objfile)
{
struct type *type;
struct symbol *sym;
type = struct_type (dip, thisdie, enddie, objfile);
if (!TYPE_STUB (type))
{
sym = new_symbol (dip, objfile);
if (sym != NULL)
{
SYMBOL_TYPE (sym) = type;
if (cu_language == language_cplus)
{
synthesize_typedef (dip, objfile, type);
}
}
}
}
static struct type *
decode_array_element_type (char *scan)
{
struct type *typep;
DIE_REF die_ref;
unsigned short attribute;
unsigned short fundtype;
int nbytes;
attribute = target_to_host (scan, SIZEOF_ATTRIBUTE, GET_UNSIGNED,
current_objfile);
scan += SIZEOF_ATTRIBUTE;
if ((nbytes = attribute_size (attribute)) == -1)
{
bad_array_element_type_complaint (DIE_ID, DIE_NAME, attribute);
typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
}
else
{
switch (attribute)
{
case AT_fund_type:
fundtype = target_to_host (scan, nbytes, GET_UNSIGNED,
current_objfile);
typep = decode_fund_type (fundtype);
break;
case AT_mod_fund_type:
typep = decode_mod_fund_type (scan);
break;
case AT_user_def_type:
die_ref = target_to_host (scan, nbytes, GET_UNSIGNED,
current_objfile);
if ((typep = lookup_utype (die_ref)) == NULL)
{
typep = alloc_utype (die_ref, NULL);
}
break;
case AT_mod_u_d_type:
typep = decode_mod_u_d_type (scan);
break;
default:
bad_array_element_type_complaint (DIE_ID, DIE_NAME, attribute);
typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
break;
}
}
return (typep);
}
static struct type *
decode_subscript_data_item (char *scan, char *end)
{
struct type *typep = NULL;
struct type *nexttype;
struct type *indextype;
struct type *rangetype;
unsigned int format;
unsigned short fundtype;
unsigned long lowbound;
unsigned long highbound;
int nbytes;
format = target_to_host (scan, SIZEOF_FORMAT_SPECIFIER, GET_UNSIGNED,
current_objfile);
scan += SIZEOF_FORMAT_SPECIFIER;
switch (format)
{
case FMT_ET:
typep = decode_array_element_type (scan);
break;
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;
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)
{
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", can't decode 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_FT_X_X:
case FMT_UT_C_C:
case FMT_UT_C_X:
case FMT_UT_X_C:
case FMT_UT_X_X:
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", array subscript format 0x%x not handled yet",
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:
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", unknown array subscript format %x", 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);
}
static void
dwarf_read_array_type (struct dieinfo *dip)
{
struct type *type;
struct type *utype;
char *sub;
char *subend;
unsigned short blocksz;
int nbytes;
if (dip->at_ordering != ORD_row_major)
{
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", array not row major; not handled correctly",
DIE_ID, DIE_NAME);
}
if ((sub = dip->at_subscr_data) != NULL)
{
nbytes = attribute_size (AT_subscr_data);
blocksz = target_to_host (sub, nbytes, GET_UNSIGNED, current_objfile);
subend = sub + nbytes + blocksz;
sub += nbytes;
type = decode_subscript_data_item (sub, subend);
if ((utype = lookup_utype (dip->die_ref)) == NULL)
{
alloc_utype (dip->die_ref, type);
}
else if (TYPE_CODE (utype) == TYPE_CODE_UNDEF)
{
*utype = *type;
}
else
{
dup_user_type_definition_complaint (DIE_ID, DIE_NAME);
}
}
}
static void
read_tag_pointer_type (struct dieinfo *dip)
{
struct type *type;
struct type *utype;
type = decode_die_type (dip);
if ((utype = lookup_utype (dip->die_ref)) == NULL)
{
utype = lookup_pointer_type (type);
alloc_utype (dip->die_ref, utype);
}
else
{
TYPE_TARGET_TYPE (utype) = type;
TYPE_POINTER_TYPE (type) = utype;
TYPE_LENGTH (utype) = TARGET_PTR_BIT / TARGET_CHAR_BIT;
TYPE_CODE (utype) = TYPE_CODE_PTR;
}
}
static void
read_tag_string_type (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)
{
highbound = dip->at_byte_size - 1;
}
else
{
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)
{
utype = alloc_utype (dip->die_ref, (struct type *) NULL);
}
else
{
if (TYPE_CODE (utype) != TYPE_CODE_UNDEF)
{
dup_user_type_definition_complaint (DIE_ID, DIE_NAME);
return;
}
}
utype = create_string_type (utype, rangetype);
}
static void
read_subroutine_type (struct dieinfo *dip, char *thisdie, char *enddie)
{
struct type *type;
struct type *ftype;
type = decode_die_type (dip);
if ((ftype = lookup_utype (dip->die_ref)) == NULL)
{
ftype = lookup_function_type (type);
alloc_utype (dip->die_ref, ftype);
}
else if (TYPE_CODE (ftype) == TYPE_CODE_UNDEF)
{
TYPE_TARGET_TYPE (ftype) = type;
TYPE_LENGTH (ftype) = 1;
TYPE_CODE (ftype) = TYPE_CODE_FUNC;
}
else
{
dup_user_type_definition_complaint (DIE_ID, DIE_NAME);
}
}
static void
read_enumeration (struct dieinfo *dip, char *thisdie, char *enddie,
struct objfile *objfile)
{
struct type *type;
struct symbol *sym;
type = enum_type (dip, objfile);
sym = new_symbol (dip, objfile);
if (sym != NULL)
{
SYMBOL_TYPE (sym) = type;
if (cu_language == language_cplus)
{
synthesize_typedef (dip, objfile, type);
}
}
}
static struct type *
enum_type (struct dieinfo *dip, struct objfile *objfile)
{
struct type *type;
struct nextfield
{
struct nextfield *next;
struct field field;
};
struct nextfield *list = NULL;
struct nextfield *new;
int nfields = 0;
int n;
char *scan;
char *listend;
unsigned short blocksz;
struct symbol *sym;
int nbytes;
int unsigned_enum = 1;
if ((type = lookup_utype (dip->die_ref)) == NULL)
{
type = alloc_utype (dip->die_ref, NULL);
}
TYPE_CODE (type) = TYPE_CODE_ENUM;
if (dip->at_name != NULL
&& *dip->at_name != '~'
&& *dip->at_name != '.')
{
TYPE_TAG_NAME (type) = obconcat (&objfile->type_obstack,
"", "", dip->at_name);
}
if (dip->at_byte_size != 0)
{
TYPE_LENGTH (type) = dip->at_byte_size;
}
if ((scan = dip->at_element_list) != NULL)
{
if (dip->short_element_list)
{
nbytes = attribute_size (AT_short_element_list);
}
else
{
nbytes = attribute_size (AT_element_list);
}
blocksz = target_to_host (scan, nbytes, GET_UNSIGNED, objfile);
listend = scan + nbytes + blocksz;
scan += nbytes;
while (scan < listend)
{
new = (struct nextfield *) alloca (sizeof (struct nextfield));
new->next = list;
list = new;
FIELD_TYPE (list->field) = NULL;
FIELD_BITSIZE (list->field) = 0;
FIELD_STATIC_KIND (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);
list->field.name = obsavestring (scan, strlen (scan),
&objfile->type_obstack);
scan += strlen (scan) + 1;
nfields++;
sym = (struct symbol *) obstack_alloc (&objfile->symbol_obstack,
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;
SYMBOL_VALUE (sym) = FIELD_BITPOS (list->field);
if (SYMBOL_VALUE (sym) < 0)
unsigned_enum = 0;
add_symbol_to_list (sym, list_in_scope);
}
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);
for (n = 0; (n < nfields) && (list != NULL); list = list->next)
{
TYPE_FIELD (type, n++) = list->field;
}
}
}
return (type);
}
static void
read_func_scope (struct dieinfo *dip, char *thisdie, char *enddie,
struct objfile *objfile)
{
register struct context_stack *new;
if (dip->at_name == NULL)
{
complaint (&symfile_complaints, "DIE @ 0x%x, AT_name tag missing",
DIE_ID);
return;
}
if (objfile->ei.entry_point >= dip->at_low_pc &&
objfile->ei.entry_point < dip->at_high_pc)
{
objfile->ei.entry_func_lowpc = dip->at_low_pc;
objfile->ei.entry_func_highpc = dip->at_high_pc;
}
new = push_context (0, dip->at_low_pc);
new->name = new_symbol (dip, objfile);
list_in_scope = &local_symbols;
process_dies (thisdie + dip->die_length, enddie, objfile);
new = pop_context ();
finish_block (new->name, &local_symbols, new->old_blocks,
new->start_addr, dip->at_high_pc, objfile);
list_in_scope = &file_symbols;
}
static void
handle_producer (char *producer)
{
if (STREQN (producer, GCC_PRODUCER, strlen (GCC_PRODUCER)))
{
char version = producer[strlen (GCC_PRODUCER)];
processing_gcc_compilation = (version == '2' ? 2 : 1);
}
else
{
processing_gcc_compilation =
STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER));
}
if (AUTO_DEMANGLING)
{
if (STREQN (producer, GPLUS_PRODUCER, strlen (GPLUS_PRODUCER)))
{
#if 0
set_demangling_style (GNU_DEMANGLING_STYLE_STRING);
#endif
}
else if (STREQN (producer, LCC_PRODUCER, strlen (LCC_PRODUCER)))
{
set_demangling_style (LUCID_DEMANGLING_STYLE_STRING);
}
}
}
static void
read_file_scope (struct dieinfo *dip, char *thisdie, char *enddie,
struct objfile *objfile)
{
struct cleanup *back_to;
struct symtab *symtab;
if (objfile->ei.entry_point >= dip->at_low_pc &&
objfile->ei.entry_point < dip->at_high_pc)
{
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)
{
handle_producer (dip->at_producer);
}
numutypes = (enddie - thisdie) / 4;
utypes = (struct type **) xmalloc (numutypes * sizeof (struct type *));
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, objfile, 0);
if (symtab != NULL)
{
symtab->language = cu_language;
}
do_cleanups (back_to);
}
static void
process_dies (char *thisdie, char *enddie, struct objfile *objfile)
{
char *nextdie;
struct dieinfo di;
while (thisdie < enddie)
{
basicdieinfo (&di, thisdie, objfile);
if (di.die_length < SIZEOF_DIE_LENGTH)
{
break;
}
else if (di.die_tag == TAG_padding)
{
nextdie = thisdie + di.die_length;
}
else
{
completedieinfo (&di, objfile);
if (di.at_sibling != 0)
{
nextdie = dbbase + di.at_sibling - dbroff;
}
else
{
nextdie = thisdie + di.die_length;
}
di.at_low_pc = SMASH_TEXT_ADDRESS (di.at_low_pc);
di.at_high_pc = SMASH_TEXT_ADDRESS (di.at_high_pc);
switch (di.die_tag)
{
case TAG_compile_unit:
if (current_subfile == NULL)
read_file_scope (&di, thisdie, nextdie, objfile);
else
nextdie = thisdie + di.die_length;
break;
case TAG_global_subroutine:
case TAG_subroutine:
if (di.has_at_low_pc)
{
read_func_scope (&di, thisdie, nextdie, objfile);
}
break;
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);
break;
case TAG_enumeration_type:
read_enumeration (&di, thisdie, nextdie, objfile);
break;
case TAG_subroutine_type:
read_subroutine_type (&di, thisdie, nextdie);
break;
case TAG_array_type:
dwarf_read_array_type (&di);
break;
case TAG_pointer_type:
read_tag_pointer_type (&di);
break;
case TAG_string_type:
read_tag_string_type (&di);
break;
default:
new_symbol (&di, objfile);
break;
}
}
thisdie = nextdie;
}
}
static void
decode_line_numbers (char *linetable)
{
char *tblscan;
char *tblend;
unsigned long length;
unsigned long base;
unsigned long line;
unsigned long pc;
if (linetable != NULL)
{
tblscan = tblend = linetable;
length = target_to_host (tblscan, SIZEOF_LINETBL_LENGTH, GET_UNSIGNED,
current_objfile);
tblscan += SIZEOF_LINETBL_LENGTH;
tblend += length;
base = target_to_host (tblscan, TARGET_FT_POINTER_SIZE (objfile),
GET_UNSIGNED, current_objfile);
tblscan += TARGET_FT_POINTER_SIZE (objfile);
base += baseaddr;
while (tblscan < tblend)
{
line = target_to_host (tblscan, SIZEOF_LINETBL_LINENO, GET_UNSIGNED,
current_objfile);
tblscan += SIZEOF_LINETBL_LINENO + SIZEOF_LINETBL_STMT;
pc = target_to_host (tblscan, SIZEOF_LINETBL_DELTA, GET_UNSIGNED,
current_objfile);
tblscan += SIZEOF_LINETBL_DELTA;
pc += base;
if (line != 0)
{
record_line (current_subfile, line, pc);
}
}
}
}
static int
locval (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;
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;
switch (loc_atom_code)
{
case 0:
loc = end;
break;
case OP_REG:
stack[++stacki]
= DWARF_REG_TO_REGNUM (target_to_host (loc, loc_value_size,
GET_UNSIGNED,
current_objfile));
loc += loc_value_size;
dip->isreg = 1;
break;
case OP_BASEREG:
dip->offreg = 1;
dip->basereg = target_to_host (loc, loc_value_size, GET_UNSIGNED,
current_objfile);
loc += loc_value_size;
stack[++stacki] = 0;
break;
case OP_ADDR:
stack[++stacki] = target_to_host (loc, loc_value_size,
GET_UNSIGNED, current_objfile);
loc += loc_value_size;
break;
case OP_CONST:
stack[++stacki] = target_to_host (loc, loc_value_size,
GET_SIGNED, current_objfile);
loc += loc_value_size;
break;
case OP_DEREF2:
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", OP_DEREF2 address 0x%lx not handled",
DIE_ID, DIE_NAME, stack[stacki]);
break;
case OP_DEREF4:
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", OP_DEREF4 address 0x%lx not handled",
DIE_ID, DIE_NAME, stack[stacki]);
break;
case OP_ADD:
stack[stacki - 1] += stack[stacki];
stacki--;
break;
}
}
return (stack[stacki]);
}
static void
read_ofile_symtab (struct partial_symtab *pst)
{
struct cleanup *back_to;
unsigned long lnsize;
file_ptr foffset;
bfd *abfd;
char lnsizedata[SIZEOF_LINETBL_LENGTH];
abfd = pst->objfile->obfd;
current_objfile = pst->objfile;
diecount = 0;
dbsize = DBLENGTH (pst);
dbbase = xmalloc (dbsize);
dbroff = DBROFF (pst);
foffset = DBFOFF (pst) + dbroff;
base_section_offsets = pst->section_offsets;
baseaddr = ANOFFSET (pst->section_offsets, 0);
if (bfd_seek (abfd, foffset, SEEK_SET) ||
(bfd_bread (dbbase, dbsize, abfd) != dbsize))
{
xfree (dbbase);
error ("can't read DWARF data");
}
back_to = make_cleanup (xfree, dbbase);
lnbase = NULL;
if (LNFOFF (pst))
{
if (bfd_seek (abfd, LNFOFF (pst), SEEK_SET) ||
(bfd_bread (lnsizedata, sizeof (lnsizedata), abfd)
!= sizeof (lnsizedata)))
{
error ("can't read DWARF line number table size");
}
lnsize = target_to_host (lnsizedata, SIZEOF_LINETBL_LENGTH,
GET_UNSIGNED, pst->objfile);
lnbase = xmalloc (lnsize);
if (bfd_seek (abfd, LNFOFF (pst), SEEK_SET) ||
(bfd_bread (lnbase, lnsize, abfd) != lnsize))
{
xfree (lnbase);
error ("can't read DWARF line numbers");
}
make_cleanup (xfree, lnbase);
}
process_dies (dbbase, dbbase + dbsize, pst->objfile);
do_cleanups (back_to);
current_objfile = NULL;
pst->symtab = pst->objfile->symtabs;
}
static void
psymtab_to_symtab_1 (struct partial_symtab *pst)
{
int i;
struct cleanup *old_chain;
if (pst != NULL)
{
if (pst->readin)
{
warning ("psymtab for %s already read in. Shouldn't happen.",
pst->filename);
}
else
{
for (i = 0; i < pst->number_of_dependencies; i++)
{
if (!pst->dependencies[i]->readin)
{
if (info_verbose)
{
fputs_filtered (" ", gdb_stdout);
wrap_here ("");
fputs_filtered ("and ", gdb_stdout);
wrap_here ("");
printf_filtered ("%s...",
pst->dependencies[i]->filename);
wrap_here ("");
gdb_flush (gdb_stdout);
}
psymtab_to_symtab_1 (pst->dependencies[i]);
}
}
if (DBLENGTH (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 ("");
gdb_flush (gdb_stdout);
}
sort_symtab_syms (pst->symtab);
do_cleanups (old_chain);
}
pst->readin = 1;
}
}
}
static void
dwarf_psymtab_to_symtab (struct partial_symtab *pst)
{
if (pst != NULL)
{
if (pst->readin)
{
warning ("psymtab for %s already read in. Shouldn't happen.",
pst->filename);
}
else
{
if (DBLENGTH (pst) || pst->number_of_dependencies)
{
if (info_verbose)
{
printf_filtered ("Reading in symbols for %s...",
pst->filename);
gdb_flush (gdb_stdout);
}
psymtab_to_symtab_1 (pst);
#if 0
scan_file_globals (pst->objfile);
#endif
if (info_verbose)
{
printf_filtered ("done.\n");
gdb_flush (gdb_stdout);
}
}
}
}
}
static void
add_enum_psymbol (struct dieinfo *dip, struct objfile *objfile)
{
char *scan;
char *listend;
unsigned short blocksz;
int nbytes;
if ((scan = dip->at_element_list) != NULL)
{
if (dip->short_element_list)
{
nbytes = attribute_size (AT_short_element_list);
}
else
{
nbytes = attribute_size (AT_element_list);
}
blocksz = target_to_host (scan, nbytes, GET_UNSIGNED, objfile);
scan += nbytes;
listend = scan + blocksz;
while (scan < listend)
{
scan += TARGET_FT_LONG_SIZE (objfile);
add_psymbol_to_list (scan, strlen (scan), VAR_NAMESPACE, LOC_CONST,
&objfile->static_psymbols, 0, 0, cu_language,
objfile);
scan += strlen (scan) + 1;
}
}
}
static void
add_partial_symbol (struct dieinfo *dip, struct objfile *objfile)
{
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,
0, dip->at_low_pc, cu_language, objfile);
break;
case TAG_global_variable:
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,
0, 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:
if (!dip->has_at_byte_size)
break;
add_psymbol_to_list (dip->at_name, strlen (dip->at_name),
STRUCT_NAMESPACE, LOC_TYPEDEF,
&objfile->static_psymbols,
0, 0, cu_language, objfile);
if (cu_language == language_cplus)
{
add_psymbol_to_list (dip->at_name, strlen (dip->at_name),
VAR_NAMESPACE, LOC_TYPEDEF,
&objfile->static_psymbols,
0, 0, cu_language, objfile);
}
break;
}
}
static void
scan_partial_symbols (char *thisdie, char *enddie, struct objfile *objfile)
{
char *nextdie;
char *temp;
struct dieinfo di;
while (thisdie < enddie)
{
basicdieinfo (&di, thisdie, objfile);
if (di.die_length < SIZEOF_DIE_LENGTH)
{
break;
}
else
{
nextdie = thisdie + di.die_length;
switch (di.die_tag)
{
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 (di.at_sibling != 0)
{
temp = dbbase + di.at_sibling - dbroff;
if ((temp < thisdie) || (temp >= enddie))
{
bad_die_ref_complaint (DIE_ID, DIE_NAME,
di.at_sibling);
}
else
{
nextdie = temp;
}
}
}
break;
case TAG_global_variable:
case TAG_local_variable:
completedieinfo (&di, objfile);
if (di.at_name && (di.has_at_low_pc || di.at_location))
{
add_partial_symbol (&di, objfile);
}
break;
case TAG_typedef:
case TAG_class_type:
case TAG_structure_type:
case TAG_union_type:
completedieinfo (&di, objfile);
if (di.at_name)
{
add_partial_symbol (&di, objfile);
}
break;
case TAG_enumeration_type:
completedieinfo (&di, objfile);
if (di.at_name)
{
add_partial_symbol (&di, objfile);
}
add_enum_psymbol (&di, objfile);
break;
}
}
thisdie = nextdie;
}
}
static void
scan_compilation_units (char *thisdie, char *enddie, file_ptr dbfoff,
file_ptr lnoffset, struct objfile *objfile)
{
char *nextdie;
struct dieinfo di;
struct partial_symtab *pst;
int culength;
int curoff;
file_ptr curlnoffset;
while (thisdie < enddie)
{
basicdieinfo (&di, thisdie, objfile);
if (di.die_length < SIZEOF_DIE_LENGTH)
{
break;
}
else if (di.die_tag != TAG_compile_unit)
{
nextdie = thisdie + di.die_length;
}
else
{
completedieinfo (&di, objfile);
set_cu_language (&di);
if (di.at_sibling != 0)
{
nextdie = dbbase + di.at_sibling - dbroff;
}
else
{
nextdie = thisdie + di.die_length;
}
curoff = thisdie - dbbase;
culength = nextdie - thisdie;
curlnoffset = di.has_at_stmt_list ? lnoffset + di.at_stmt_list : 0;
pst = start_psymtab_common (objfile, base_section_offsets,
di.at_name, di.at_low_pc,
objfile->global_psymbols.next,
objfile->static_psymbols.next);
pst->texthigh = di.at_high_pc;
pst->read_symtab_private = (char *)
obstack_alloc (&objfile->psymbol_obstack,
sizeof (struct dwfinfo));
DBFOFF (pst) = dbfoff;
DBROFF (pst) = curoff;
DBLENGTH (pst) = culength;
LNFOFF (pst) = curlnoffset;
pst->read_symtab = dwarf_psymtab_to_symtab;
scan_partial_symbols (thisdie + di.die_length, nextdie, objfile);
pst->n_global_syms = objfile->global_psymbols.next -
(objfile->global_psymbols.list + pst->globals_offset);
pst->n_static_syms = objfile->static_psymbols.next -
(objfile->static_psymbols.list + pst->statics_offset);
sort_pst_symbols (pst);
free_named_symtabs (pst->filename);
}
thisdie = nextdie;
}
}
static struct symbol *
new_symbol (struct dieinfo *dip, struct objfile *objfile)
{
struct symbol *sym = NULL;
if (dip->at_name != NULL)
{
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);
SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
SYMBOL_CLASS (sym) = LOC_STATIC;
SYMBOL_TYPE (sym) = decode_die_type (dip);
SYMBOL_LANGUAGE (sym) = cu_language;
SYMBOL_INIT_DEMANGLED_NAME (sym, &objfile->symbol_obstack);
switch (dip->die_tag)
{
case TAG_label:
SYMBOL_VALUE_ADDRESS (sym) = dip->at_low_pc;
SYMBOL_CLASS (sym) = LOC_LABEL;
break;
case TAG_global_subroutine:
case TAG_subroutine:
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)
{
add_symbol_to_list (sym, &global_symbols);
}
else
{
add_symbol_to_list (sym, list_in_scope);
}
break;
case TAG_global_variable:
if (dip->at_location != NULL)
{
SYMBOL_VALUE_ADDRESS (sym) = locval (dip);
add_symbol_to_list (sym, &global_symbols);
SYMBOL_CLASS (sym) = LOC_STATIC;
SYMBOL_VALUE (sym) += baseaddr;
}
break;
case TAG_local_variable:
if (dip->at_location != NULL)
{
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 (dip->offreg)
{
SYMBOL_CLASS (sym) = LOC_BASEREG;
SYMBOL_BASEREG (sym) = dip->basereg;
}
else
{
SYMBOL_CLASS (sym) = LOC_STATIC;
SYMBOL_VALUE (sym) += baseaddr;
}
if (SYMBOL_CLASS (sym) == LOC_STATIC)
{
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);
}
add_symbol_to_list (sym, list_in_scope);
if (dip->isreg)
{
SYMBOL_CLASS (sym) = LOC_REGPARM;
}
else if (dip->offreg)
{
SYMBOL_CLASS (sym) = LOC_BASEREG_ARG;
SYMBOL_BASEREG (sym) = dip->basereg;
}
else
{
SYMBOL_CLASS (sym) = LOC_ARG;
}
break;
case TAG_unspecified_parameters:
break;
case TAG_class_type:
case TAG_structure_type:
case TAG_union_type:
case TAG_enumeration_type:
SYMBOL_CLASS (sym) = LOC_TYPEDEF;
SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
add_symbol_to_list (sym, list_in_scope);
break;
case TAG_typedef:
SYMBOL_CLASS (sym) = LOC_TYPEDEF;
SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE;
add_symbol_to_list (sym, list_in_scope);
break;
default:
break;
}
}
return (sym);
}
static void
synthesize_typedef (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));
OBJSTAT (objfile, n_syms++);
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);
}
}
static struct type *
decode_mod_fund_type (char *typedata)
{
struct type *typep = NULL;
unsigned short modcount;
int nbytes;
nbytes = attribute_size (AT_mod_fund_type);
modcount = target_to_host (typedata, nbytes, GET_UNSIGNED, current_objfile);
typedata += nbytes;
modcount -= attribute_size (AT_fund_type);
typep = decode_modified_type (typedata, modcount, AT_mod_fund_type);
return (typep);
}
static struct type *
decode_mod_u_d_type (char *typedata)
{
struct type *typep = NULL;
unsigned short modcount;
int nbytes;
nbytes = attribute_size (AT_mod_u_d_type);
modcount = target_to_host (typedata, nbytes, GET_UNSIGNED, current_objfile);
typedata += nbytes;
modcount -= attribute_size (AT_user_def_type);
typep = decode_modified_type (typedata, modcount, AT_mod_u_d_type);
return (typep);
}
static struct type *
decode_modified_type (char *modifiers, unsigned int modcount, int mtype)
{
struct type *typep = NULL;
unsigned short fundtype;
DIE_REF die_ref;
char modifier;
int nbytes;
if (modcount == 0)
{
switch (mtype)
{
case AT_mod_fund_type:
nbytes = attribute_size (AT_fund_type);
fundtype = target_to_host (modifiers, nbytes, GET_UNSIGNED,
current_objfile);
typep = decode_fund_type (fundtype);
break;
case AT_mod_u_d_type:
nbytes = attribute_size (AT_user_def_type);
die_ref = target_to_host (modifiers, nbytes, GET_UNSIGNED,
current_objfile);
if ((typep = lookup_utype (die_ref)) == NULL)
{
typep = alloc_utype (die_ref, NULL);
}
break;
default:
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", botched modified type decoding (mtype 0x%x)",
DIE_ID, DIE_NAME, mtype);
typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
break;
}
}
else
{
modifier = *modifiers++;
typep = decode_modified_type (modifiers, --modcount, mtype);
switch (modifier)
{
case MOD_pointer_to:
typep = lookup_pointer_type (typep);
break;
case MOD_reference_to:
typep = lookup_reference_type (typep);
break;
case MOD_const:
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", type modifier 'const' ignored", DIE_ID,
DIE_NAME);
break;
case MOD_volatile:
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", type modifier 'volatile' ignored",
DIE_ID, DIE_NAME);
break;
default:
if (!(MOD_lo_user <= (unsigned char) modifier
&& (unsigned char) modifier <= MOD_hi_user))
{
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", unknown type modifier %u", DIE_ID,
DIE_NAME, modifier);
}
break;
}
}
return (typep);
}
static struct type *
decode_fund_type (unsigned int fundtype)
{
struct type *typep = NULL;
switch (fundtype)
{
case FT_void:
typep = dwarf_fundamental_type (current_objfile, FT_VOID);
break;
case FT_boolean:
typep = dwarf_fundamental_type (current_objfile, FT_BOOLEAN);
break;
case FT_pointer:
typep = dwarf_fundamental_type (current_objfile, FT_VOID);
typep = lookup_pointer_type (typep);
break;
case FT_char:
typep = dwarf_fundamental_type (current_objfile, FT_CHAR);
break;
case FT_signed_char:
typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_CHAR);
break;
case FT_unsigned_char:
typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_CHAR);
break;
case FT_short:
typep = dwarf_fundamental_type (current_objfile, FT_SHORT);
break;
case FT_signed_short:
typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_SHORT);
break;
case FT_unsigned_short:
typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_SHORT);
break;
case FT_integer:
typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
break;
case FT_signed_integer:
typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_INTEGER);
break;
case FT_unsigned_integer:
typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_INTEGER);
break;
case FT_long:
typep = dwarf_fundamental_type (current_objfile, FT_LONG);
break;
case FT_signed_long:
typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG);
break;
case FT_unsigned_long:
typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG);
break;
case FT_long_long:
typep = dwarf_fundamental_type (current_objfile, FT_LONG_LONG);
break;
case FT_signed_long_long:
typep = dwarf_fundamental_type (current_objfile, FT_SIGNED_LONG_LONG);
break;
case FT_unsigned_long_long:
typep = dwarf_fundamental_type (current_objfile, FT_UNSIGNED_LONG_LONG);
break;
case FT_float:
typep = dwarf_fundamental_type (current_objfile, FT_FLOAT);
break;
case FT_dbl_prec_float:
typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_FLOAT);
break;
case FT_ext_prec_float:
typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_FLOAT);
break;
case FT_complex:
typep = dwarf_fundamental_type (current_objfile, FT_COMPLEX);
break;
case FT_dbl_prec_complex:
typep = dwarf_fundamental_type (current_objfile, FT_DBL_PREC_COMPLEX);
break;
case FT_ext_prec_complex:
typep = dwarf_fundamental_type (current_objfile, FT_EXT_PREC_COMPLEX);
break;
}
if (typep == NULL)
{
typep = dwarf_fundamental_type (current_objfile, FT_INTEGER);
if (!(FT_lo_user <= fundtype && fundtype <= FT_hi_user))
{
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", unexpected fundamental type 0x%x",
DIE_ID, DIE_NAME, fundtype);
}
}
return (typep);
}
static char *
create_name (char *name, struct obstack *obstackp)
{
int length;
char *newname;
length = strlen (name) + 1;
newname = (char *) obstack_alloc (obstackp, length);
strcpy (newname, name);
return (newname);
}
static void
basicdieinfo (struct dieinfo *dip, char *diep, struct objfile *objfile)
{
curdie = dip;
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) ||
((diep + dip->die_length) > (dbbase + dbsize)))
{
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", malformed DIE, bad length (%ld bytes)",
DIE_ID, DIE_NAME, dip->die_length);
dip->die_length = 0;
}
else if (dip->die_length < (SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG))
{
dip->die_tag = TAG_padding;
}
else
{
diep += SIZEOF_DIE_LENGTH;
dip->die_tag = target_to_host (diep, SIZEOF_DIE_TAG, GET_UNSIGNED,
objfile);
}
}
static void
completedieinfo (struct dieinfo *dip, struct objfile *objfile)
{
char *diep;
char *end;
unsigned short attr;
unsigned short form;
int nbytes;
diecount++;
diep = dip->die;
end = diep + dip->die_length;
diep += SIZEOF_DIE_LENGTH + SIZEOF_DIE_TAG;
while (diep < end)
{
attr = target_to_host (diep, SIZEOF_ATTRIBUTE, GET_UNSIGNED, objfile);
diep += SIZEOF_ATTRIBUTE;
if ((nbytes = attribute_size (attr)) == -1)
{
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", unknown attribute length, skipped remaining attributes",
DIE_ID, DIE_NAME);
diep = end;
continue;
}
switch (attr)
{
case AT_fund_type:
dip->at_fund_type = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
case AT_ordering:
dip->at_ordering = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
case AT_bit_offset:
dip->at_bit_offset = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
case AT_sibling:
dip->at_sibling = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
case AT_stmt_list:
dip->at_stmt_list = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
dip->has_at_stmt_list = 1;
break;
case AT_low_pc:
dip->at_low_pc = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
dip->at_low_pc += baseaddr;
dip->has_at_low_pc = 1;
break;
case AT_high_pc:
dip->at_high_pc = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
dip->at_high_pc += baseaddr;
break;
case AT_language:
dip->at_language = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
case AT_user_def_type:
dip->at_user_def_type = target_to_host (diep, nbytes,
GET_UNSIGNED, objfile);
break;
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,
objfile);
break;
case AT_member:
dip->at_member = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
case AT_discr:
dip->at_discr = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
case AT_location:
dip->at_location = diep;
break;
case AT_mod_fund_type:
dip->at_mod_fund_type = diep;
break;
case AT_subscr_data:
dip->at_subscr_data = diep;
break;
case AT_mod_u_d_type:
dip->at_mod_u_d_type = diep;
break;
case AT_element_list:
dip->at_element_list = diep;
dip->short_element_list = 0;
break;
case AT_short_element_list:
dip->at_element_list = diep;
dip->short_element_list = 1;
break;
case AT_discr_value:
dip->at_discr_value = diep;
break;
case AT_string_length:
dip->at_string_length = diep;
break;
case AT_name:
dip->at_name = diep;
break;
case AT_comp_dir:
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_start_scope:
dip->at_start_scope = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
case AT_stride_size:
dip->at_stride_size = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
case AT_src_info:
dip->at_src_info = target_to_host (diep, nbytes, GET_UNSIGNED,
objfile);
break;
case AT_prototyped:
dip->at_prototyped = diep;
break;
default:
break;
}
form = FORM_FROM_ATTR (attr);
switch (form)
{
case FORM_DATA2:
diep += 2;
break;
case FORM_DATA4:
case FORM_REF:
diep += 4;
break;
case FORM_DATA8:
diep += 8;
break;
case FORM_ADDR:
diep += TARGET_FT_POINTER_SIZE (objfile);
break;
case FORM_BLOCK2:
diep += 2 + target_to_host (diep, nbytes, GET_UNSIGNED, objfile);
break;
case FORM_BLOCK4:
diep += 4 + target_to_host (diep, nbytes, GET_UNSIGNED, objfile);
break;
case FORM_STRING:
diep += strlen (diep) + 1;
break;
default:
unknown_attribute_form_complaint (DIE_ID, DIE_NAME, form);
diep = end;
break;
}
}
}
static CORE_ADDR
target_to_host (char *from, int nbytes, int signextend,
struct objfile *objfile)
{
CORE_ADDR rtnval;
switch (nbytes)
{
case 8:
rtnval = bfd_get_64 (objfile->obfd, (bfd_byte *) from);
break;
case 4:
rtnval = bfd_get_32 (objfile->obfd, (bfd_byte *) from);
break;
case 2:
rtnval = bfd_get_16 (objfile->obfd, (bfd_byte *) from);
break;
case 1:
rtnval = bfd_get_8 (objfile->obfd, (bfd_byte *) from);
break;
default:
complaint (&symfile_complaints,
"DIE @ 0x%x \"%s\", no bfd support for %d byte data object",
DIE_ID, DIE_NAME, nbytes);
rtnval = 0;
break;
}
return (rtnval);
}
static int
attribute_size (unsigned int attr)
{
int nbytes;
unsigned short form;
form = FORM_FROM_ATTR (attr);
switch (form)
{
case FORM_STRING:
nbytes = 0;
break;
case FORM_DATA2:
case FORM_BLOCK2:
nbytes = 2;
break;
case FORM_DATA4:
case FORM_BLOCK4:
case FORM_REF:
nbytes = 4;
break;
case FORM_DATA8:
nbytes = 8;
break;
case FORM_ADDR:
nbytes = TARGET_FT_POINTER_SIZE (objfile);
break;
default:
unknown_attribute_form_complaint (DIE_ID, DIE_NAME, form);
nbytes = -1;
break;
}
return (nbytes);
}