blob: 4cf2b1d7121a3f47265157cfb14626d40bbbe97b [file] [log] [blame]
/* ieee.c -- Read and write IEEE-695 debugging information.
Copyright (C) 1996-2016 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
/* This file reads and writes IEEE-695 debugging information. */
#include "sysdep.h"
#include <assert.h>
#include "bfd.h"
#include "ieee.h"
#include "libiberty.h"
#include "debug.h"
#include "budbg.h"
#include "filenames.h"
/* This structure holds an entry on the block stack. */
struct ieee_block
{
/* The kind of block. */
int kind;
/* The source file name, for a BB5 block. */
const char *filename;
/* The index of the function type, for a BB4 or BB6 block. */
unsigned int fnindx;
/* TRUE if this function is being skipped. */
bfd_boolean skip;
};
/* This structure is the block stack. */
#define BLOCKSTACK_SIZE (16)
struct ieee_blockstack
{
/* The stack pointer. */
struct ieee_block *bsp;
/* The stack. */
struct ieee_block stack[BLOCKSTACK_SIZE];
};
/* This structure holds information for a variable. */
enum ieee_var_kind
{
IEEE_UNKNOWN,
IEEE_EXTERNAL,
IEEE_GLOBAL,
IEEE_STATIC,
IEEE_LOCAL,
IEEE_FUNCTION
};
struct ieee_var
{
/* Start of name. */
const char *name;
/* Length of name. */
unsigned long namlen;
/* Type. */
debug_type type;
/* Slot if we make an indirect type. */
debug_type *pslot;
/* Kind of variable or function. */
enum ieee_var_kind kind;
};
/* This structure holds all the variables. */
struct ieee_vars
{
/* Number of slots allocated. */
unsigned int alloc;
/* Variables. */
struct ieee_var *vars;
};
/* This structure holds information for a type. We need this because
we don't want to represent bitfields as real types. */
struct ieee_type
{
/* Type. */
debug_type type;
/* Slot if this is type is referenced before it is defined. */
debug_type *pslot;
/* Slots for arguments if we make indirect types for them. */
debug_type *arg_slots;
/* If this is a bitfield, this is the size in bits. If this is not
a bitfield, this is zero. */
unsigned long bitsize;
};
/* This structure holds all the type information. */
struct ieee_types
{
/* Number of slots allocated. */
unsigned int alloc;
/* Types. */
struct ieee_type *types;
/* Builtin types. */
#define BUILTIN_TYPE_COUNT (60)
debug_type builtins[BUILTIN_TYPE_COUNT];
};
/* This structure holds a linked last of structs with their tag names,
so that we can convert them to C++ classes if necessary. */
struct ieee_tag
{
/* Next tag. */
struct ieee_tag *next;
/* This tag name. */
const char *name;
/* The type of the tag. */
debug_type type;
/* The tagged type is an indirect type pointing at this slot. */
debug_type slot;
/* This is an array of slots used when a field type is converted
into a indirect type, in case it needs to be later converted into
a reference type. */
debug_type *fslots;
};
/* This structure holds the information we pass around to the parsing
functions. */
struct ieee_info
{
/* The debugging handle. */
void *dhandle;
/* The BFD. */
bfd *abfd;
/* The start of the bytes to be parsed. */
const bfd_byte *bytes;
/* The end of the bytes to be parsed. */
const bfd_byte *pend;
/* The block stack. */
struct ieee_blockstack blockstack;
/* Whether we have seen a BB1 or BB2. */
bfd_boolean saw_filename;
/* The variables. */
struct ieee_vars vars;
/* The global variables, after a global typedef block. */
struct ieee_vars *global_vars;
/* The types. */
struct ieee_types types;
/* The global types, after a global typedef block. */
struct ieee_types *global_types;
/* The list of tagged structs. */
struct ieee_tag *tags;
};
/* Basic builtin types, not including the pointers. */
enum builtin_types
{
builtin_unknown = 0,
builtin_void = 1,
builtin_signed_char = 2,
builtin_unsigned_char = 3,
builtin_signed_short_int = 4,
builtin_unsigned_short_int = 5,
builtin_signed_long = 6,
builtin_unsigned_long = 7,
builtin_signed_long_long = 8,
builtin_unsigned_long_long = 9,
builtin_float = 10,
builtin_double = 11,
builtin_long_double = 12,
builtin_long_long_double = 13,
builtin_quoted_string = 14,
builtin_instruction_address = 15,
builtin_int = 16,
builtin_unsigned = 17,
builtin_unsigned_int = 18,
builtin_char = 19,
builtin_long = 20,
builtin_short = 21,
builtin_unsigned_short = 22,
builtin_short_int = 23,
builtin_signed_short = 24,
builtin_bcd_float = 25
};
/* These are the values found in the derivation flags of a 'b'
component record of a 'T' type extension record in a C++ pmisc
record. These are bitmasks. */
/* Set for a private base class, clear for a public base class.
Protected base classes are not supported. */
#define BASEFLAGS_PRIVATE (0x1)
/* Set for a virtual base class. */
#define BASEFLAGS_VIRTUAL (0x2)
/* Set for a friend class, clear for a base class. */
#define BASEFLAGS_FRIEND (0x10)
/* These are the values found in the specs flags of a 'd', 'm', or 'v'
component record of a 'T' type extension record in a C++ pmisc
record. The same flags are used for a 'M' record in a C++ pmisc
record. */
/* The lower two bits hold visibility information. */
#define CXXFLAGS_VISIBILITY (0x3)
/* This value in the lower two bits indicates a public member. */
#define CXXFLAGS_VISIBILITY_PUBLIC (0x0)
/* This value in the lower two bits indicates a private member. */
#define CXXFLAGS_VISIBILITY_PRIVATE (0x1)
/* This value in the lower two bits indicates a protected member. */
#define CXXFLAGS_VISIBILITY_PROTECTED (0x2)
/* Set for a static member. */
#define CXXFLAGS_STATIC (0x4)
/* Set for a virtual override. */
#define CXXFLAGS_OVERRIDE (0x8)
/* Set for a friend function. */
#define CXXFLAGS_FRIEND (0x10)
/* Set for a const function. */
#define CXXFLAGS_CONST (0x20)
/* Set for a volatile function. */
#define CXXFLAGS_VOLATILE (0x40)
/* Set for an overloaded function. */
#define CXXFLAGS_OVERLOADED (0x80)
/* Set for an operator function. */
#define CXXFLAGS_OPERATOR (0x100)
/* Set for a constructor or destructor. */
#define CXXFLAGS_CTORDTOR (0x400)
/* Set for a constructor. */
#define CXXFLAGS_CTOR (0x200)
/* Set for an inline function. */
#define CXXFLAGS_INLINE (0x800)
/* Local functions. */
static void ieee_error (struct ieee_info *, const bfd_byte *, const char *);
static void ieee_eof (struct ieee_info *);
static char *savestring (const char *, unsigned long);
static bfd_boolean ieee_read_number
(struct ieee_info *, const bfd_byte **, bfd_vma *);
static bfd_boolean ieee_read_optional_number
(struct ieee_info *, const bfd_byte **, bfd_vma *, bfd_boolean *);
static bfd_boolean ieee_read_id
(struct ieee_info *, const bfd_byte **, const char **, unsigned long *);
static bfd_boolean ieee_read_optional_id
(struct ieee_info *, const bfd_byte **, const char **, unsigned long *,
bfd_boolean *);
static bfd_boolean ieee_read_expression
(struct ieee_info *, const bfd_byte **, bfd_vma *);
static debug_type ieee_builtin_type
(struct ieee_info *, const bfd_byte *, unsigned int);
static bfd_boolean ieee_alloc_type
(struct ieee_info *, unsigned int, bfd_boolean);
static bfd_boolean ieee_read_type_index
(struct ieee_info *, const bfd_byte **, debug_type *);
static int ieee_regno_to_genreg (bfd *, int);
static int ieee_genreg_to_regno (bfd *, int);
static bfd_boolean parse_ieee_bb (struct ieee_info *, const bfd_byte **);
static bfd_boolean parse_ieee_be (struct ieee_info *, const bfd_byte **);
static bfd_boolean parse_ieee_nn (struct ieee_info *, const bfd_byte **);
static bfd_boolean parse_ieee_ty (struct ieee_info *, const bfd_byte **);
static bfd_boolean parse_ieee_atn (struct ieee_info *, const bfd_byte **);
static bfd_boolean ieee_read_cxx_misc
(struct ieee_info *, const bfd_byte **, unsigned long);
static bfd_boolean ieee_read_cxx_class
(struct ieee_info *, const bfd_byte **, unsigned long);
static bfd_boolean ieee_read_cxx_defaults
(struct ieee_info *, const bfd_byte **, unsigned long);
static bfd_boolean ieee_read_reference
(struct ieee_info *, const bfd_byte **);
static bfd_boolean ieee_require_asn
(struct ieee_info *, const bfd_byte **, bfd_vma *);
static bfd_boolean ieee_require_atn65
(struct ieee_info *, const bfd_byte **, const char **, unsigned long *);
/* Report an error in the IEEE debugging information. */
static void
ieee_error (struct ieee_info *info, const bfd_byte *p, const char *s)
{
if (p != NULL)
fprintf (stderr, "%s: 0x%lx: %s (0x%x)\n", bfd_get_filename (info->abfd),
(unsigned long) (p - info->bytes), s, *p);
else
fprintf (stderr, "%s: %s\n", bfd_get_filename (info->abfd), s);
}
/* Report an unexpected EOF in the IEEE debugging information. */
static void
ieee_eof (struct ieee_info *info)
{
ieee_error (info, (const bfd_byte *) NULL,
_("unexpected end of debugging information"));
}
/* Save a string in memory. */
static char *
savestring (const char *start, unsigned long len)
{
char *ret;
ret = (char *) xmalloc (len + 1);
memcpy (ret, start, len);
ret[len] = '\0';
return ret;
}
/* Read a number which must be present in an IEEE file. */
static bfd_boolean
ieee_read_number (struct ieee_info *info, const bfd_byte **pp, bfd_vma *pv)
{
return ieee_read_optional_number (info, pp, pv, (bfd_boolean *) NULL);
}
/* Read a number in an IEEE file. If ppresent is not NULL, the number
need not be there. */
static bfd_boolean
ieee_read_optional_number (struct ieee_info *info, const bfd_byte **pp,
bfd_vma *pv, bfd_boolean *ppresent)
{
ieee_record_enum_type b;
if (*pp >= info->pend)
{
if (ppresent != NULL)
{
*ppresent = FALSE;
return TRUE;
}
ieee_eof (info);
return FALSE;
}
b = (ieee_record_enum_type) **pp;
++*pp;
if (b <= ieee_number_end_enum)
{
*pv = (bfd_vma) b;
if (ppresent != NULL)
*ppresent = TRUE;
return TRUE;
}
if (b >= ieee_number_repeat_start_enum && b <= ieee_number_repeat_end_enum)
{
unsigned int i;
i = (int) b - (int) ieee_number_repeat_start_enum;
if (*pp + i - 1 >= info->pend)
{
ieee_eof (info);
return FALSE;
}
*pv = 0;
for (; i > 0; i--)
{
*pv <<= 8;
*pv += **pp;
++*pp;
}
if (ppresent != NULL)
*ppresent = TRUE;
return TRUE;
}
if (ppresent != NULL)
{
--*pp;
*ppresent = FALSE;
return TRUE;
}
ieee_error (info, *pp - 1, _("invalid number"));
return FALSE;
}
/* Read a required string from an IEEE file. */
static bfd_boolean
ieee_read_id (struct ieee_info *info, const bfd_byte **pp,
const char **pname, unsigned long *pnamlen)
{
return ieee_read_optional_id (info, pp, pname, pnamlen, (bfd_boolean *) NULL);
}
/* Read a string from an IEEE file. If ppresent is not NULL, the
string is optional. */
static bfd_boolean
ieee_read_optional_id (struct ieee_info *info, const bfd_byte **pp,
const char **pname, unsigned long *pnamlen,
bfd_boolean *ppresent)
{
bfd_byte b;
unsigned long len;
if (*pp >= info->pend)
{
ieee_eof (info);
return FALSE;
}
b = **pp;
++*pp;
if (b <= 0x7f)
len = b;
else if ((ieee_record_enum_type) b == ieee_extension_length_1_enum)
{
len = **pp;
++*pp;
}
else if ((ieee_record_enum_type) b == ieee_extension_length_2_enum)
{
len = (**pp << 8) + (*pp)[1];
*pp += 2;
}
else
{
if (ppresent != NULL)
{
--*pp;
*ppresent = FALSE;
return TRUE;
}
ieee_error (info, *pp - 1, _("invalid string length"));
return FALSE;
}
if ((unsigned long) (info->pend - *pp) < len)
{
ieee_eof (info);
return FALSE;
}
*pname = (const char *) *pp;
*pnamlen = len;
*pp += len;
if (ppresent != NULL)
*ppresent = TRUE;
return TRUE;
}
/* Read an expression from an IEEE file. Since this code is only used
to parse debugging information, I haven't bothered to write a full
blown IEEE expression parser. I've only thrown in the things I've
seen in debugging information. This can be easily extended if
necessary. */
static bfd_boolean
ieee_read_expression (struct ieee_info *info, const bfd_byte **pp,
bfd_vma *pv)
{
const bfd_byte *expr_start;
#define EXPR_STACK_SIZE (10)
bfd_vma expr_stack[EXPR_STACK_SIZE];
bfd_vma *esp;
expr_start = *pp;
esp = expr_stack;
while (1)
{
const bfd_byte *start;
bfd_vma val;
bfd_boolean present;
ieee_record_enum_type c;
start = *pp;
if (! ieee_read_optional_number (info, pp, &val, &present))
return FALSE;
if (present)
{
if (esp - expr_stack >= EXPR_STACK_SIZE)
{
ieee_error (info, start, _("expression stack overflow"));
return FALSE;
}
*esp++ = val;
continue;
}
c = (ieee_record_enum_type) **pp;
if (c >= ieee_module_beginning_enum)
break;
++*pp;
if (c == ieee_comma)
break;
switch (c)
{
default:
ieee_error (info, start, _("unsupported IEEE expression operator"));
break;
case ieee_variable_R_enum:
{
bfd_vma indx;
asection *s;
if (! ieee_read_number (info, pp, &indx))
return FALSE;
for (s = info->abfd->sections; s != NULL; s = s->next)
if ((bfd_vma) s->target_index == indx)
break;
if (s == NULL)
{
ieee_error (info, start, _("unknown section"));
return FALSE;
}
if (esp - expr_stack >= EXPR_STACK_SIZE)
{
ieee_error (info, start, _("expression stack overflow"));
return FALSE;
}
*esp++ = bfd_get_section_vma (info->abfd, s);
}
break;
case ieee_function_plus_enum:
case ieee_function_minus_enum:
{
bfd_vma v1, v2;
if (esp - expr_stack < 2)
{
ieee_error (info, start, _("expression stack underflow"));
return FALSE;
}
v1 = *--esp;
v2 = *--esp;
*esp++ = v1 + v2;
}
break;
}
}
if (esp - 1 != expr_stack)
{
ieee_error (info, expr_start, _("expression stack mismatch"));
return FALSE;
}
*pv = *--esp;
return TRUE;
}
/* Return an IEEE builtin type. */
static debug_type
ieee_builtin_type (struct ieee_info *info, const bfd_byte *p,
unsigned int indx)
{
void *dhandle;
debug_type type;
const char *name;
if (indx < BUILTIN_TYPE_COUNT
&& info->types.builtins[indx] != DEBUG_TYPE_NULL)
return info->types.builtins[indx];
dhandle = info->dhandle;
if (indx >= 32 && indx < 64)
{
type = debug_make_pointer_type (dhandle,
ieee_builtin_type (info, p, indx - 32));
assert (indx < BUILTIN_TYPE_COUNT);
info->types.builtins[indx] = type;
return type;
}
switch ((enum builtin_types) indx)
{
default:
ieee_error (info, p, _("unknown builtin type"));
return NULL;
case builtin_unknown:
type = debug_make_void_type (dhandle);
name = NULL;
break;
case builtin_void:
type = debug_make_void_type (dhandle);
name = "void";
break;
case builtin_signed_char:
type = debug_make_int_type (dhandle, 1, FALSE);
name = "signed char";
break;
case builtin_unsigned_char:
type = debug_make_int_type (dhandle, 1, TRUE);
name = "unsigned char";
break;
case builtin_signed_short_int:
type = debug_make_int_type (dhandle, 2, FALSE);
name = "signed short int";
break;
case builtin_unsigned_short_int:
type = debug_make_int_type (dhandle, 2, TRUE);
name = "unsigned short int";
break;
case builtin_signed_long:
type = debug_make_int_type (dhandle, 4, FALSE);
name = "signed long";
break;
case builtin_unsigned_long:
type = debug_make_int_type (dhandle, 4, TRUE);
name = "unsigned long";
break;
case builtin_signed_long_long:
type = debug_make_int_type (dhandle, 8, FALSE);
name = "signed long long";
break;
case builtin_unsigned_long_long:
type = debug_make_int_type (dhandle, 8, TRUE);
name = "unsigned long long";
break;
case builtin_float:
type = debug_make_float_type (dhandle, 4);
name = "float";
break;
case builtin_double:
type = debug_make_float_type (dhandle, 8);
name = "double";
break;
case builtin_long_double:
/* FIXME: The size for this type should depend upon the
processor. */
type = debug_make_float_type (dhandle, 12);
name = "long double";
break;
case builtin_long_long_double:
type = debug_make_float_type (dhandle, 16);
name = "long long double";
break;
case builtin_quoted_string:
type = debug_make_array_type (dhandle,
ieee_builtin_type (info, p,
((unsigned int)
builtin_char)),
ieee_builtin_type (info, p,
((unsigned int)
builtin_int)),
0, -1, TRUE);
name = "QUOTED STRING";
break;
case builtin_instruction_address:
/* FIXME: This should be a code address. */
type = debug_make_int_type (dhandle, 4, TRUE);
name = "instruction address";
break;
case builtin_int:
/* FIXME: The size for this type should depend upon the
processor. */
type = debug_make_int_type (dhandle, 4, FALSE);
name = "int";
break;
case builtin_unsigned:
/* FIXME: The size for this type should depend upon the
processor. */
type = debug_make_int_type (dhandle, 4, TRUE);
name = "unsigned";
break;
case builtin_unsigned_int:
/* FIXME: The size for this type should depend upon the
processor. */
type = debug_make_int_type (dhandle, 4, TRUE);
name = "unsigned int";
break;
case builtin_char:
type = debug_make_int_type (dhandle, 1, FALSE);
name = "char";
break;
case builtin_long:
type = debug_make_int_type (dhandle, 4, FALSE);
name = "long";
break;
case builtin_short:
type = debug_make_int_type (dhandle, 2, FALSE);
name = "short";
break;
case builtin_unsigned_short:
type = debug_make_int_type (dhandle, 2, TRUE);
name = "unsigned short";
break;
case builtin_short_int:
type = debug_make_int_type (dhandle, 2, FALSE);
name = "short int";
break;
case builtin_signed_short:
type = debug_make_int_type (dhandle, 2, FALSE);
name = "signed short";
break;
case builtin_bcd_float:
ieee_error (info, p, _("BCD float type not supported"));
return DEBUG_TYPE_NULL;
}
if (name != NULL)
type = debug_name_type (dhandle, name, type);
assert (indx < BUILTIN_TYPE_COUNT);
info->types.builtins[indx] = type;
return type;
}
/* Allocate more space in the type table. If ref is TRUE, this is a
reference to the type; if it is not already defined, we should set
up an indirect type. */
static bfd_boolean
ieee_alloc_type (struct ieee_info *info, unsigned int indx, bfd_boolean ref)
{
unsigned int nalloc;
register struct ieee_type *t;
struct ieee_type *tend;
if (indx >= info->types.alloc)
{
nalloc = info->types.alloc;
if (nalloc == 0)
nalloc = 4;
while (indx >= nalloc)
nalloc *= 2;
info->types.types = ((struct ieee_type *)
xrealloc (info->types.types,
nalloc * sizeof *info->types.types));
memset (info->types.types + info->types.alloc, 0,
(nalloc - info->types.alloc) * sizeof *info->types.types);
tend = info->types.types + nalloc;
for (t = info->types.types + info->types.alloc; t < tend; t++)
t->type = DEBUG_TYPE_NULL;
info->types.alloc = nalloc;
}
if (ref)
{
t = info->types.types + indx;
if (t->type == NULL)
{
t->pslot = (debug_type *) xmalloc (sizeof *t->pslot);
*t->pslot = DEBUG_TYPE_NULL;
t->type = debug_make_indirect_type (info->dhandle, t->pslot,
(const char *) NULL);
if (t->type == NULL)
return FALSE;
}
}
return TRUE;
}
/* Read a type index and return the corresponding type. */
static bfd_boolean
ieee_read_type_index (struct ieee_info *info, const bfd_byte **pp,
debug_type *ptype)
{
const bfd_byte *start;
bfd_vma indx;
start = *pp;
if (! ieee_read_number (info, pp, &indx))
return FALSE;
if (indx < 256)
{
*ptype = ieee_builtin_type (info, start, indx);
if (*ptype == NULL)
return FALSE;
return TRUE;
}
indx -= 256;
if (! ieee_alloc_type (info, indx, TRUE))
return FALSE;
*ptype = info->types.types[indx].type;
return TRUE;
}
/* Parse IEEE debugging information for a file. This is passed the
bytes which compose the Debug Information Part of an IEEE file. */
bfd_boolean
parse_ieee (void *dhandle, bfd *abfd, const bfd_byte *bytes, bfd_size_type len)
{
struct ieee_info info;
unsigned int i;
const bfd_byte *p, *pend;
info.dhandle = dhandle;
info.abfd = abfd;
info.bytes = bytes;
info.pend = bytes + len;
info.blockstack.bsp = info.blockstack.stack;
info.saw_filename = FALSE;
info.vars.alloc = 0;
info.vars.vars = NULL;
info.global_vars = NULL;
info.types.alloc = 0;
info.types.types = NULL;
info.global_types = NULL;
info.tags = NULL;
for (i = 0; i < BUILTIN_TYPE_COUNT; i++)
info.types.builtins[i] = DEBUG_TYPE_NULL;
p = bytes;
pend = info.pend;
while (p < pend)
{
const bfd_byte *record_start;
ieee_record_enum_type c;
record_start = p;
c = (ieee_record_enum_type) *p++;
if (c == ieee_at_record_enum)
c = (ieee_record_enum_type) (((unsigned int) c << 8) | *p++);
if (c <= ieee_number_repeat_end_enum)
{
ieee_error (&info, record_start, _("unexpected number"));
return FALSE;
}
switch (c)
{
default:
ieee_error (&info, record_start, _("unexpected record type"));
return FALSE;
case ieee_bb_record_enum:
if (! parse_ieee_bb (&info, &p))
return FALSE;
break;
case ieee_be_record_enum:
if (! parse_ieee_be (&info, &p))
return FALSE;
break;
case ieee_nn_record:
if (! parse_ieee_nn (&info, &p))
return FALSE;
break;
case ieee_ty_record_enum:
if (! parse_ieee_ty (&info, &p))
return FALSE;
break;
case ieee_atn_record_enum:
if (! parse_ieee_atn (&info, &p))
return FALSE;
break;
}
}
if (info.blockstack.bsp != info.blockstack.stack)
{
ieee_error (&info, (const bfd_byte *) NULL,
_("blocks left on stack at end"));
return FALSE;
}
return TRUE;
}
/* Handle an IEEE BB record. */
static bfd_boolean
parse_ieee_bb (struct ieee_info *info, const bfd_byte **pp)
{
const bfd_byte *block_start;
bfd_byte b;
bfd_vma size;
const char *name;
unsigned long namlen;
char *namcopy = NULL;
unsigned int fnindx;
bfd_boolean skip;
block_start = *pp;
b = **pp;
++*pp;
if (! ieee_read_number (info, pp, &size)
|| ! ieee_read_id (info, pp, &name, &namlen))
return FALSE;
fnindx = (unsigned int) -1;
skip = FALSE;
switch (b)
{
case 1:
/* BB1: Type definitions local to a module. */
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_set_filename (info->dhandle, namcopy))
return FALSE;
info->saw_filename = TRUE;
/* Discard any variables or types we may have seen before. */
if (info->vars.vars != NULL)
free (info->vars.vars);
info->vars.vars = NULL;
info->vars.alloc = 0;
if (info->types.types != NULL)
free (info->types.types);
info->types.types = NULL;
info->types.alloc = 0;
/* Initialize the types to the global types. */
if (info->global_types != NULL)
{
info->types.alloc = info->global_types->alloc;
info->types.types = ((struct ieee_type *)
xmalloc (info->types.alloc
* sizeof (*info->types.types)));
memcpy (info->types.types, info->global_types->types,
info->types.alloc * sizeof (*info->types.types));
}
break;
case 2:
/* BB2: Global type definitions. The name is supposed to be
empty, but we don't check. */
if (! debug_set_filename (info->dhandle, "*global*"))
return FALSE;
info->saw_filename = TRUE;
break;
case 3:
/* BB3: High level module block begin. We don't have to do
anything here. The name is supposed to be the same as for
the BB1, but we don't check. */
break;
case 4:
/* BB4: Global function. */
{
bfd_vma stackspace, typindx, offset;
debug_type return_type;
if (! ieee_read_number (info, pp, &stackspace)
|| ! ieee_read_number (info, pp, &typindx)
|| ! ieee_read_expression (info, pp, &offset))
return FALSE;
/* We have no way to record the stack space. FIXME. */
if (typindx < 256)
{
return_type = ieee_builtin_type (info, block_start, typindx);
if (return_type == DEBUG_TYPE_NULL)
return FALSE;
}
else
{
typindx -= 256;
if (! ieee_alloc_type (info, typindx, TRUE))
return FALSE;
fnindx = typindx;
return_type = info->types.types[typindx].type;
if (debug_get_type_kind (info->dhandle, return_type)
== DEBUG_KIND_FUNCTION)
return_type = debug_get_return_type (info->dhandle,
return_type);
}
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_record_function (info->dhandle, namcopy, return_type,
TRUE, offset))
return FALSE;
}
break;
case 5:
/* BB5: File name for source line numbers. */
{
unsigned int i;
/* We ignore the date and time. FIXME. */
for (i = 0; i < 6; i++)
{
bfd_vma ignore;
bfd_boolean present;
if (! ieee_read_optional_number (info, pp, &ignore, &present))
return FALSE;
if (! present)
break;
}
if (! info->saw_filename)
{
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_set_filename (info->dhandle, namcopy))
return FALSE;
info->saw_filename = TRUE;
}
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_start_source (info->dhandle, namcopy))
return FALSE;
}
break;
case 6:
/* BB6: Local function or block. */
{
bfd_vma stackspace, typindx, offset;
if (! ieee_read_number (info, pp, &stackspace)
|| ! ieee_read_number (info, pp, &typindx)
|| ! ieee_read_expression (info, pp, &offset))
return FALSE;
/* We have no way to record the stack space. FIXME. */
if (namlen == 0)
{
if (! debug_start_block (info->dhandle, offset))
return FALSE;
/* Change b to indicate that this is a block
rather than a function. */
b = 0x86;
}
else
{
/* The MRI C++ compiler will output a fake function named
__XRYCPP to hold C++ debugging information. We skip
that function. This is not crucial, but it makes
converting from IEEE to other debug formats work
better. */
if (strncmp (name, "__XRYCPP", namlen) == 0)
skip = TRUE;
else
{
debug_type return_type;
if (typindx < 256)
{
return_type = ieee_builtin_type (info, block_start,
typindx);
if (return_type == NULL)
return FALSE;
}
else
{
typindx -= 256;
if (! ieee_alloc_type (info, typindx, TRUE))
return FALSE;
fnindx = typindx;
return_type = info->types.types[typindx].type;
if (debug_get_type_kind (info->dhandle, return_type)
== DEBUG_KIND_FUNCTION)
return_type = debug_get_return_type (info->dhandle,
return_type);
}
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_record_function (info->dhandle, namcopy,
return_type, FALSE, offset))
return FALSE;
}
}
}
break;
case 10:
/* BB10: Assembler module scope. In the normal case, we
completely ignore all this information. FIXME. */
{
const char *inam, *vstr;
unsigned long inamlen, vstrlen;
bfd_vma tool_type;
bfd_boolean present;
unsigned int i;
if (! info->saw_filename)
{
namcopy = savestring (name, namlen);
if (namcopy == NULL)
return FALSE;
if (! debug_set_filename (info->dhandle, namcopy))
return FALSE;
info->saw_filename = TRUE;
}
if (! ieee_read_id (info, pp, &inam, &inamlen)
|| ! ieee_read_number (info, pp, &tool_type)
|| ! ieee_read_optional_id (info, pp, &vstr, &vstrlen, &present))
return FALSE;
for (i = 0; i < 6; i++)
{
bfd_vma ignore;
if (! ieee_read_optional_number (info, pp, &ignore, &present))
return FALSE;
if (! present)
break;
}
}
break;
case 11:
/* BB11: Module section. We completely ignore all this
information. FIXME. */
{
bfd_vma sectype, secindx, offset, map;
bfd_boolean present;
if (! ieee_read_number (info, pp, &sectype)
|| ! ieee_read_number (info, pp, &secindx)
|| ! ieee_read_expression (info, pp, &offset)
|| ! ieee_read_optional_number (info, pp, &map, &present))
return FALSE;
}
break;
default:
ieee_error (info, block_start, _("unknown BB type"));
return FALSE;
}
/* Push this block on the block stack. */
if (info->blockstack.bsp >= info->blockstack.stack + BLOCKSTACK_SIZE)
{
ieee_error (info, (const bfd_byte *) NULL, _("stack overflow"));
return FALSE;
}
info->blockstack.bsp->kind = b;
if (b == 5)
info->blockstack.bsp->filename = namcopy;
info->blockstack.bsp->fnindx = fnindx;
info->blockstack.bsp->skip = skip;
++info->blockstack.bsp;
return TRUE;
}
/* Handle an IEEE BE record. */
static bfd_boolean
parse_ieee_be (struct ieee_info *info, const bfd_byte **pp)
{
bfd_vma offset;
if (info->blockstack.bsp <= info->blockstack.stack)
{
ieee_error (info, *pp, _("stack underflow"));
return FALSE;
}
--info->blockstack.bsp;
switch (info->blockstack.bsp->kind)
{
case 2:
/* When we end the global typedefs block, we copy out the
contents of info->vars. This is because the variable indices
may be reused in the local blocks. However, we need to
preserve them so that we can locate a function returning a
reference variable whose type is named in the global typedef
block. */
info->global_vars = ((struct ieee_vars *)
xmalloc (sizeof *info->global_vars));
info->global_vars->alloc = info->vars.alloc;
info->global_vars->vars = ((struct ieee_var *)
xmalloc (info->vars.alloc
* sizeof (*info->vars.vars)));
memcpy (info->global_vars->vars, info->vars.vars,
info->vars.alloc * sizeof (*info->vars.vars));
/* We also copy out the non builtin parts of info->types, since
the types are discarded when we start a new block. */
info->global_types = ((struct ieee_types *)
xmalloc (sizeof *info->global_types));
info->global_types->alloc = info->types.alloc;
info->global_types->types = ((struct ieee_type *)
xmalloc (info->types.alloc
* sizeof (*info->types.types)));
memcpy (info->global_types->types, info->types.types,
info->types.alloc * sizeof (*info->types.types));
memset (info->global_types->builtins, 0,
sizeof (info->global_types->builtins));
break;
case 4:
case 6:
if (! ieee_read_expression (info, pp, &offset))
return FALSE;
if (! info->blockstack.bsp->skip)
{
if (! debug_end_function (info->dhandle, offset + 1))
return FALSE;
}
break;
case 0x86:
/* This is BE6 when BB6 started a block rather than a local
function. */
if (! ieee_read_expression (info, pp, &offset))
return FALSE;
if (! debug_end_block (info->dhandle, offset + 1))
return FALSE;
break;
case 5:
/* When we end a BB5, we look up the stack for the last BB5, if
there is one, so that we can call debug_start_source. */
if (info->blockstack.bsp > info->blockstack.stack)
{
struct ieee_block *bl;
bl = info->blockstack.bsp;
do
{
--bl;
if (bl->kind == 5)
{
if (! debug_start_source (info->dhandle, bl->filename))
return FALSE;
break;
}
}
while (bl != info->blockstack.stack);
}
break;
case 11:
if (! ieee_read_expression (info, pp, &offset))
return FALSE;
/* We just ignore the module size. FIXME. */
break;
default:
/* Other block types do not have any trailing information. */
break;
}
return TRUE;
}
/* Parse an NN record. */
static bfd_boolean
parse_ieee_nn (struct ieee_info *info, const bfd_byte **pp)
{
const bfd_byte *nn_start;
bfd_vma varindx;
const char *name;
unsigned long namlen;
nn_start = *pp;
if (! ieee_read_number (info, pp, &varindx)
|| ! ieee_read_id (info, pp, &name, &namlen))
return FALSE;
if (varindx < 32)
{
ieee_error (info, nn_start, _("illegal variable index"));
return FALSE;
}
varindx -= 32;
if (varindx >= info->vars.alloc)
{
unsigned int alloc;
alloc = info->vars.alloc;
if (alloc == 0)
alloc = 4;
while (varindx >= alloc)
alloc *= 2;
info->vars.vars = ((struct ieee_var *)
xrealloc (info->vars.vars,
alloc * sizeof *info->vars.vars));
memset (info->vars.vars + info->vars.alloc, 0,
(alloc - info->vars.alloc) * sizeof *info->vars.vars);
info->vars.alloc = alloc;
}
info->vars.vars[varindx].name = name;
info->vars.vars[varindx].namlen = namlen;
return TRUE;
}
/* Parse a TY record. */
static bfd_boolean
parse_ieee_ty (struct ieee_info *info, const bfd_byte **pp)
{
const bfd_byte *ty_start, *ty_var_start, *ty_code_start;
bfd_vma typeindx, varindx, tc;
void *dhandle;
bfd_boolean tag, typdef;
debug_type *arg_slots;
unsigned long type_bitsize;
debug_type type;
ty_start = *pp;
if (! ieee_read_number (info, pp, &typeindx))
return FALSE;
if (typeindx < 256)
{
ieee_error (info, ty_start, _("illegal type index"));
return FALSE;
}
typeindx -= 256;
if (! ieee_alloc_type (info, typeindx, FALSE))
return FALSE;
if (**pp != 0xce)
{
ieee_error (info, *pp, _("unknown TY code"));
return FALSE;
}
++*pp;
ty_var_start = *pp;
if (! ieee_read_number (info, pp, &varindx))
return FALSE;
if (varindx < 32)
{
ieee_error (info, ty_var_start, _("illegal variable index"));
return FALSE;
}
varindx -= 32;
if (varindx >= info->vars.alloc || info->vars.vars[varindx].name == NULL)
{
ieee_error (info, ty_var_start, _("undefined variable in TY"));
return FALSE;
}
ty_code_start = *pp;
if (! ieee_read_number (info, pp, &tc))
return FALSE;
dhandle = info->dhandle;
tag = FALSE;
typdef = FALSE;
arg_slots = NULL;
type_bitsize = 0;
switch (tc)
{
default:
ieee_error (info, ty_code_start, _("unknown TY code"));
return FALSE;
case '!':
/* Unknown type, with size. We treat it as int. FIXME. */
{
bfd_vma size;
if (! ieee_read_number (info, pp, &size))
return FALSE;
type = debug_make_int_type (dhandle, size, FALSE);
}
break;
case 'A': /* Array. */
case 'a': /* FORTRAN array in column/row order. FIXME: Not
distinguished from normal array. */
{
debug_type ele_type;
bfd_vma lower, upper;
if (! ieee_read_type_index (info, pp, &ele_type)
|| ! ieee_read_number (info, pp, &lower)
|| ! ieee_read_number (info, pp, &upper))
return FALSE;
type = debug_make_array_type (dhandle, ele_type,
ieee_builtin_type (info, ty_code_start,
((unsigned int)
builtin_int)),
(bfd_signed_vma) lower,
(bfd_signed_vma) upper,
FALSE);
}
break;
case 'E':
/* Simple enumeration. */
{
bfd_vma size;
unsigned int alloc;
const char **names;
unsigned int c;
bfd_signed_vma *vals;
unsigned int i;
if (! ieee_read_number (info, pp, &size))
return FALSE;
/* FIXME: we ignore the enumeration size. */
alloc = 10;
names = (const char **) xmalloc (alloc * sizeof *names);
memset (names, 0, alloc * sizeof *names);
c = 0;
while (1)
{
const char *name;
unsigned long namlen;
bfd_boolean present;
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
if (! present)
break;
if (c + 1 >= alloc)
{
alloc += 10;
names = ((const char **)
xrealloc (names, alloc * sizeof *names));
}
names[c] = savestring (name, namlen);
if (names[c] == NULL)
return FALSE;
++c;
}
names[c] = NULL;
vals = (bfd_signed_vma *) xmalloc (c * sizeof *vals);
for (i = 0; i < c; i++)
vals[i] = i;
type = debug_make_enum_type (dhandle, names, vals);
tag = TRUE;
}
break;
case 'G':
/* Struct with bit fields. */
{
bfd_vma size;
unsigned int alloc;
debug_field *fields;
unsigned int c;
if (! ieee_read_number (info, pp, &size))
return FALSE;
alloc = 10;
fields = (debug_field *) xmalloc (alloc * sizeof *fields);
c = 0;
while (1)
{
const char *name;
unsigned long namlen;
bfd_boolean present;
debug_type ftype;
bfd_vma bitpos, bitsize;
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
if (! present)
break;
if (! ieee_read_type_index (info, pp, &ftype)
|| ! ieee_read_number (info, pp, &bitpos)
|| ! ieee_read_number (info, pp, &bitsize))
return FALSE;
if (c + 1 >= alloc)
{
alloc += 10;
fields = ((debug_field *)
xrealloc (fields, alloc * sizeof *fields));
}
fields[c] = debug_make_field (dhandle, savestring (name, namlen),
ftype, bitpos, bitsize,
DEBUG_VISIBILITY_PUBLIC);
if (fields[c] == NULL)
return FALSE;
++c;
}
fields[c] = NULL;
type = debug_make_struct_type (dhandle, TRUE, size, fields);
tag = TRUE;
}
break;
case 'N':
/* Enumeration. */
{
unsigned int alloc;
const char **names;
bfd_signed_vma *vals;
unsigned int c;
alloc = 10;
names = (const char **) xmalloc (alloc * sizeof *names);
vals = (bfd_signed_vma *) xmalloc (alloc * sizeof *names);
c = 0;
while (1)
{
const char *name;
unsigned long namlen;
bfd_boolean present;
bfd_vma val;
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
if (! present)
break;
if (! ieee_read_number (info, pp, &val))
return FALSE;
/* If the length of the name is zero, then the value is
actually the size of the enum. We ignore this
information. FIXME. */
if (namlen == 0)
continue;
if (c + 1 >= alloc)
{
alloc += 10;
names = ((const char **)
xrealloc (names, alloc * sizeof *names));
vals = ((bfd_signed_vma *)
xrealloc (vals, alloc * sizeof *vals));
}
names[c] = savestring (name, namlen);
if (names[c] == NULL)
return FALSE;
vals[c] = (bfd_signed_vma) val;
++c;
}
names[c] = NULL;
type = debug_make_enum_type (dhandle, names, vals);
tag = TRUE;
}
break;
case 'O': /* Small pointer. We don't distinguish small and large
pointers. FIXME. */
case 'P': /* Large pointer. */
{
debug_type t;
if (! ieee_read_type_index (info, pp, &t))
return FALSE;
type = debug_make_pointer_type (dhandle, t);
}
break;
case 'R':
/* Range. */
{
bfd_vma low, high, signedp, size;
if (! ieee_read_number (info, pp, &low)
|| ! ieee_read_number (info, pp, &high)
|| ! ieee_read_number (info, pp, &signedp)
|| ! ieee_read_number (info, pp, &size))
return FALSE;
type = debug_make_range_type (dhandle,
debug_make_int_type (dhandle, size,
! signedp),
(bfd_signed_vma) low,
(bfd_signed_vma) high);
}
break;
case 'S': /* Struct. */
case 'U': /* Union. */
{
bfd_vma size;
unsigned int alloc;
debug_field *fields;
unsigned int c;
if (! ieee_read_number (info, pp, &size))
return FALSE;
alloc = 10;
fields = (debug_field *) xmalloc (alloc * sizeof *fields);
c = 0;
while (1)
{
const char *name;
unsigned long namlen;
bfd_boolean present;
bfd_vma tindx;
bfd_vma offset;
debug_type ftype;
bfd_vma bitsize;
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
if (! present)
break;
if (! ieee_read_number (info, pp, &tindx)
|| ! ieee_read_number (info, pp, &offset))
return FALSE;
if (tindx < 256)
{
ftype = ieee_builtin_type (info, ty_code_start, tindx);
bitsize = 0;
offset *= 8;
}
else
{
struct ieee_type *t;
tindx -= 256;
if (! ieee_alloc_type (info, tindx, TRUE))
return FALSE;
t = info->types.types + tindx;
ftype = t->type;
bitsize = t->bitsize;
if (bitsize == 0)
offset *= 8;
}
if (c + 1 >= alloc)
{
alloc += 10;
fields = ((debug_field *)
xrealloc (fields, alloc * sizeof *fields));
}
fields[c] = debug_make_field (dhandle, savestring (name, namlen),
ftype, offset, bitsize,
DEBUG_VISIBILITY_PUBLIC);
if (fields[c] == NULL)
return FALSE;
++c;
}
fields[c] = NULL;
type = debug_make_struct_type (dhandle, tc == 'S', size, fields);
tag = TRUE;
}
break;
case 'T':
/* Typedef. */
if (! ieee_read_type_index (info, pp, &type))
return FALSE;
typdef = TRUE;
break;
case 'X':
/* Procedure. FIXME: This is an extern declaration, which we
have no way of representing. */
{
bfd_vma attr;
debug_type rtype;
bfd_vma nargs;
bfd_boolean present;
struct ieee_var *pv;
/* FIXME: We ignore the attribute and the argument names. */
if (! ieee_read_number (info, pp, &attr)
|| ! ieee_read_type_index (info, pp, &rtype)
|| ! ieee_read_number (info, pp, &nargs))
return FALSE;
do
{
const char *name;
unsigned long namlen;
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
}
while (present);
pv = info->vars.vars + varindx;
pv->kind = IEEE_EXTERNAL;
if (pv->namlen > 0
&& debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER)
{
/* Set up the return type as an indirect type pointing to
the variable slot, so that we can change it to a
reference later if appropriate. */
pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot);
*pv->pslot = rtype;
rtype = debug_make_indirect_type (dhandle, pv->pslot,
(const char *) NULL);
}
type = debug_make_function_type (dhandle, rtype, (debug_type *) NULL,
FALSE);
}
break;
case 'V':
case 'v':
/* Void. This is not documented, but the MRI compiler emits it. */
type = debug_make_void_type (dhandle);
break;
case 'Z':
/* Array with 0 lower bound. */
{
debug_type etype;
bfd_vma high;
if (! ieee_read_type_index (info, pp, &etype)
|| ! ieee_read_number (info, pp, &high))
return FALSE;
type = debug_make_array_type (dhandle, etype,
ieee_builtin_type (info, ty_code_start,
((unsigned int)
builtin_int)),
0, (bfd_signed_vma) high, FALSE);
}
break;
case 'c': /* Complex. */
case 'd': /* Double complex. */
{
const char *name;
unsigned long namlen;
/* FIXME: I don't know what the name means. */
if (! ieee_read_id (info, pp, &name, &namlen))
return FALSE;
type = debug_make_complex_type (dhandle, tc == 'c' ? 4 : 8);
}
break;
case 'f':
/* Pascal file name. FIXME. */
ieee_error (info, ty_code_start, _("Pascal file name not supported"));
return FALSE;
case 'g':
/* Bitfield type. */
{
bfd_vma signedp, bitsize, dummy;
const bfd_byte *hold;
bfd_boolean present;
if (! ieee_read_number (info, pp, &signedp)
|| ! ieee_read_number (info, pp, &bitsize))
return FALSE;
/* I think the documentation says that there is a type index,
but some actual files do not have one. */
hold = *pp;
if (! ieee_read_optional_number (info, pp, &dummy, &present))
return FALSE;
if (! present)
{
/* FIXME: This is just a guess. */
type = debug_make_int_type (dhandle, 4,
signedp ? FALSE : TRUE);
}
else
{
*pp = hold;
if (! ieee_read_type_index (info, pp, &type))
return FALSE;
}
type_bitsize = bitsize;
}
break;
case 'n':
/* Qualifier. */
{
bfd_vma kind;
debug_type t;
if (! ieee_read_number (info, pp, &kind)
|| ! ieee_read_type_index (info, pp, &t))
return FALSE;
switch (kind)
{
default:
ieee_error (info, ty_start, _("unsupported qualifier"));
return FALSE;
case 1:
type = debug_make_const_type (dhandle, t);
break;
case 2:
type = debug_make_volatile_type (dhandle, t);
break;
}
}
break;
case 's':
/* Set. */
{
bfd_vma size;
debug_type etype;
if (! ieee_read_number (info, pp, &size)
|| ! ieee_read_type_index (info, pp, &etype))
return FALSE;
/* FIXME: We ignore the size. */
type = debug_make_set_type (dhandle, etype, FALSE);
}
break;
case 'x':
/* Procedure with compiler dependencies. */
{
struct ieee_var *pv;
bfd_vma attr, frame_type, push_mask, nargs, level, father;
debug_type rtype;
debug_type *arg_types;
bfd_boolean varargs;
bfd_boolean present;
/* FIXME: We ignore some of this information. */
pv = info->vars.vars + varindx;
if (! ieee_read_number (info, pp, &attr)
|| ! ieee_read_number (info, pp, &frame_type)
|| ! ieee_read_number (info, pp, &push_mask)
|| ! ieee_read_type_index (info, pp, &rtype)
|| ! ieee_read_number (info, pp, &nargs))
return FALSE;
if (nargs == (bfd_vma) -1)
{
arg_types = NULL;
varargs = FALSE;
}
else
{
unsigned int i;
arg_types = ((debug_type *)
xmalloc ((nargs + 1) * sizeof *arg_types));
for (i = 0; i < nargs; i++)
if (! ieee_read_type_index (info, pp, arg_types + i))
return FALSE;
/* If the last type is pointer to void, this is really a
varargs function. */
varargs = FALSE;
if (nargs > 0)
{
debug_type last;
last = arg_types[nargs - 1];
if (debug_get_type_kind (dhandle, last) == DEBUG_KIND_POINTER
&& (debug_get_type_kind (dhandle,
debug_get_target_type (dhandle,
last))
== DEBUG_KIND_VOID))
{
--nargs;
varargs = TRUE;
}
}
/* If there are any pointer arguments, turn them into
indirect types in case we later need to convert them to
reference types. */
for (i = 0; i < nargs; i++)
{
if (debug_get_type_kind (dhandle, arg_types[i])
== DEBUG_KIND_POINTER)
{
if (arg_slots == NULL)
{
arg_slots = ((debug_type *)
xmalloc (nargs * sizeof *arg_slots));
memset (arg_slots, 0, nargs * sizeof *arg_slots);
}
arg_slots[i] = arg_types[i];
arg_types[i] =
debug_make_indirect_type (dhandle,
arg_slots + i,
(const char *) NULL);
}
}
arg_types[nargs] = DEBUG_TYPE_NULL;
}
if (! ieee_read_number (info, pp, &level)
|| ! ieee_read_optional_number (info, pp, &father, &present))
return FALSE;
/* We can't distinguish between a global function and a static
function. */
pv->kind = IEEE_FUNCTION;
if (pv->namlen > 0
&& debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER)
{
/* Set up the return type as an indirect type pointing to
the variable slot, so that we can change it to a
reference later if appropriate. */
pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot);
*pv->pslot = rtype;
rtype = debug_make_indirect_type (dhandle, pv->pslot,
(const char *) NULL);
}
type = debug_make_function_type (dhandle, rtype, arg_types, varargs);
}
break;
}
/* Record the type in the table. */
if (type == DEBUG_TYPE_NULL)
return FALSE;
info->vars.vars[varindx].type = type;
if ((tag || typdef)
&& info->vars.vars[varindx].namlen > 0)
{
const char *name;
name = savestring (info->vars.vars[varindx].name,
info->vars.vars[varindx].namlen);
if (typdef)
type = debug_name_type (dhandle, name, type);
else if (tc == 'E' || tc == 'N')
type = debug_tag_type (dhandle, name, type);
else
{
struct ieee_tag *it;
/* We must allocate all struct tags as indirect types, so
that if we later see a definition of the tag as a C++
record we can update the indirect slot and automatically
change all the existing references. */
it = (struct ieee_tag *) xmalloc (sizeof *it);
memset (it, 0, sizeof *it);
it->next = info->tags;
info->tags = it;
it->name = name;
it->slot = type;
type = debug_make_indirect_type (dhandle, &it->slot, name);
type = debug_tag_type (dhandle, name, type);
it->type = type;
}
if (type == NULL)
return FALSE;
}
info->types.types[typeindx].type = type;
info->types.types[typeindx].arg_slots = arg_slots;
info->types.types[typeindx].bitsize = type_bitsize;
/* We may have already allocated type as an indirect type pointing
to slot. It does no harm to replace the indirect type with the
real type. Filling in slot as well handles the indirect types
which are already hanging around. */
if (info->types.types[typeindx].pslot != NULL)
*info->types.types[typeindx].pslot = type;
return TRUE;
}
/* Parse an ATN record. */
static bfd_boolean
parse_ieee_atn (struct ieee_info *info, const bfd_byte **pp)
{
const bfd_byte *atn_start, *atn_code_start;
bfd_vma varindx;
struct ieee_var *pvar;
debug_type type;
bfd_vma atn_code;
void *dhandle;
bfd_vma v, v2, v3, v4, v5;
const char *name;
unsigned long namlen;
char *namcopy;
bfd_boolean present;
int blocktype;
atn_start = *pp;
if (! ieee_read_number (info, pp, &varindx)
|| ! ieee_read_type_index (info, pp, &type))
return FALSE;
atn_code_start = *pp;
if (! ieee_read_number (info, pp, &atn_code))
return FALSE;
if (varindx == 0)
{
pvar = NULL;
name = "";
namlen = 0;
}
else if (varindx < 32)
{
/* The MRI compiler reportedly sometimes emits variable lifetime
information for a register. We just ignore it. */
if (atn_code == 9)
return ieee_read_number (info, pp, &v);
ieee_error (info, atn_start, _("illegal variable index"));
return FALSE;
}
else
{
varindx -= 32;
if (varindx >= info->vars.alloc
|| info->vars.vars[varindx].name == NULL)
{
/* The MRI compiler or linker sometimes omits the NN record
for a pmisc record. */
if (atn_code == 62)
{
if (varindx >= info->vars.alloc)
{
unsigned int alloc;
alloc = info->vars.alloc;
if (alloc == 0)
alloc = 4;
while (varindx >= alloc)
alloc *= 2;
info->vars.vars = ((struct ieee_var *)
xrealloc (info->vars.vars,
(alloc
* sizeof *info->vars.vars)));
memset (info->vars.vars + info->vars.alloc, 0,
((alloc - info->vars.alloc)
* sizeof *info->vars.vars));
info->vars.alloc = alloc;
}
pvar = info->vars.vars + varindx;
pvar->name = "";
pvar->namlen = 0;
}
else
{
ieee_error (info, atn_start, _("undefined variable in ATN"));
return FALSE;
}
}
pvar = info->vars.vars + varindx;
pvar->type = type;
name = pvar->name;
namlen = pvar->namlen;
}
dhandle = info->dhandle;
/* If we are going to call debug_record_variable with a pointer
type, change the type to an indirect type so that we can later
change it to a reference type if we encounter a C++ pmisc 'R'
record. */
if (pvar != NULL
&& type != DEBUG_TYPE_NULL
&& debug_get_type_kind (dhandle, type) == DEBUG_KIND_POINTER)
{
switch (atn_code)
{
case 1:
case 2:
case 3:
case 5:
case 8:
case 10:
pvar->pslot = (debug_type *) xmalloc (sizeof *pvar->pslot);
*pvar->pslot = type;
type = debug_make_indirect_type (dhandle, pvar->pslot,
(const char *) NULL);
pvar->type = type;
break;
}
}
switch (atn_code)
{
default:
ieee_error (info, atn_code_start, _("unknown ATN type"));
return FALSE;
case 1:
/* Automatic variable. */
if (! ieee_read_number (info, pp, &v))
return FALSE;
namcopy = savestring (name, namlen);
if (type == NULL)
type = debug_make_void_type (dhandle);
if (pvar != NULL)
pvar->kind = IEEE_LOCAL;
return debug_record_variable (dhandle, namcopy, type, DEBUG_LOCAL, v);
case 2:
/* Register variable. */
if (! ieee_read_number (info, pp, &v))
return FALSE;
namcopy = savestring (name, namlen);
if (type == NULL)
type = debug_make_void_type (dhandle);
if (pvar != NULL)
pvar->kind = IEEE_LOCAL;
return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER,
ieee_regno_to_genreg (info->abfd, v));
case 3:
/* Static variable. */
if (! ieee_require_asn (info, pp, &v))
return FALSE;
namcopy = savestring (name, namlen);
if (type == NULL)
type = debug_make_void_type (dhandle);
if (info->blockstack.bsp <= info->blockstack.stack)
blocktype = 0;
else
blocktype = info->blockstack.bsp[-1].kind;
if (pvar != NULL)
{
if (blocktype == 4 || blocktype == 6)
pvar->kind = IEEE_LOCAL;
else
pvar->kind = IEEE_STATIC;
}
return debug_record_variable (dhandle, namcopy, type,
(blocktype == 4 || blocktype == 6
? DEBUG_LOCAL_STATIC
: DEBUG_STATIC),
v);
case 4:
/* External function. We don't currently record these. FIXME. */
if (pvar != NULL)
pvar->kind = IEEE_EXTERNAL;
return TRUE;
case 5:
/* External variable. We don't currently record these. FIXME. */
if (pvar != NULL)
pvar->kind = IEEE_EXTERNAL;
return TRUE;
case 7:
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_number (info, pp, &v2)
|| ! ieee_read_optional_number (info, pp, &v3, &present))
return FALSE;
if (present)
{
if (! ieee_read_optional_number (info, pp, &v4, &present))
return FALSE;
}
/* We just ignore the two optional fields in v3 and v4, since
they are not defined. */
if (! ieee_require_asn (info, pp, &v3))
return FALSE;
/* We have no way to record the column number. FIXME. */
return debug_record_line (dhandle, v, v3);
case 8:
/* Global variable. */
if (! ieee_require_asn (info, pp, &v))
return FALSE;
namcopy = savestring (name, namlen);
if (type == NULL)
type = debug_make_void_type (dhandle);
if (pvar != NULL)
pvar->kind = IEEE_GLOBAL;
return debug_record_variable (dhandle, namcopy, type, DEBUG_GLOBAL, v);
case 9:
/* Variable lifetime information. */
if (! ieee_read_number (info, pp, &v))
return FALSE;
/* We have no way to record this information. FIXME. */
return TRUE;
case 10:
/* Locked register. The spec says that there are two required
fields, but at least on occasion the MRI compiler only emits
one. */
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_optional_number (info, pp, &v2, &present))
return FALSE;
/* I think this means a variable that is both in a register and
a frame slot. We ignore the frame slot. FIXME. */
namcopy = savestring (name, namlen);
if (type == NULL)
type = debug_make_void_type (dhandle);
if (pvar != NULL)
pvar->kind = IEEE_LOCAL;
return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, v);
case 11:
/* Reserved for FORTRAN common. */
ieee_error (info, atn_code_start, _("unsupported ATN11"));
/* Return TRUE to keep going. */
return TRUE;
case 12:
/* Based variable. */
v3 = 0;
v4 = 0x80;
v5 = 0;
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_number (info, pp, &v2)
|| ! ieee_read_optional_number (info, pp, &v3, &present))
return FALSE;
if (present)
{
if (! ieee_read_optional_number (info, pp, &v4, &present))
return FALSE;
if (present)
{
if (! ieee_read_optional_number (info, pp, &v5, &present))
return FALSE;
}
}
/* We have no way to record this information. FIXME. */
ieee_error (info, atn_code_start, _("unsupported ATN12"));
/* Return TRUE to keep going. */
return TRUE;
case 16:
/* Constant. The description of this that I have is ambiguous,
so I'm not going to try to implement it. */
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_optional_number (info, pp, &v2, &present))
return FALSE;
if (present)
{
if (! ieee_read_optional_number (info, pp, &v2, &present))
return FALSE;
if (present)
{
if (! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
}
}
if ((ieee_record_enum_type) **pp == ieee_e2_first_byte_enum)
{
if (! ieee_require_asn (info, pp, &v3))
return FALSE;
}
return TRUE;
case 19:
/* Static variable from assembler. */
v2 = 0;
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_optional_number (info, pp, &v2, &present)
|| ! ieee_require_asn (info, pp, &v3))
return FALSE;
namcopy = savestring (name, namlen);
/* We don't really handle this correctly. FIXME. */
return debug_record_variable (dhandle, namcopy,
debug_make_void_type (dhandle),
v2 != 0 ? DEBUG_GLOBAL : DEBUG_STATIC,
v3);
case 62:
/* Procedure miscellaneous information. */
case 63:
/* Variable miscellaneous information. */
case 64:
/* Module miscellaneous information. */
if (! ieee_read_number (info, pp, &v)
|| ! ieee_read_number (info, pp, &v2)
|| ! ieee_read_optional_id (info, pp, &name, &namlen, &present))
return FALSE;
if (atn_code == 62 && v == 80)
{
if (present)
{
ieee_error (info, atn_code_start,
_("unexpected string in C++ misc"));
return FALSE;
}
return ieee_read_cxx_misc (info, pp, v2);
}
/* We just ignore all of this stuff. FIXME. */
for (; v2 > 0; --v2)
{
switch ((ieee_record_enum_type) **pp)
{
default:
ieee_error (info, *pp, _("bad misc record"));
return FALSE;
case ieee_at_record_enum:
if (! ieee_require_atn65 (info, pp, &name, &namlen))
return FALSE;
break;
case ieee_e2_first_byte_enum:
if (! ieee_require_asn (info, pp, &v3))
return FALSE;
break;
}
}
return TRUE;
}
/*NOTREACHED*/
}
/* Handle C++ debugging miscellaneous records. This is called for
procedure miscellaneous records of type 80. */
static bfd_boolean
ieee_read_cxx_misc (struct ieee_info *info, const bfd_byte **pp,
unsigned long count)
{
const bfd_byte *start;
bfd_vma category;
start = *pp;
/* Get the category of C++ misc record. */
if (! ieee_require_asn (info, pp, &category))
return FALSE;
--count;
switch (category)
{
default:
ieee_error (info, start, _("unrecognized C++ misc record"));
return FALSE;
case 'T':
if (! ieee_read_cxx_class (info, pp, count))
return FALSE;
break;
case 'M':
{
bfd_vma flags;
const char *name;
unsigned long namlen;
/* The IEEE spec indicates that the 'M' record only has a
flags field. The MRI compiler also emits the name of the
function. */
if (! ieee_require_asn (info, pp, &flags))
return FALSE;
if (*pp < info->pend
&& (ieee_record_enum_type) **pp == ieee_at_record_enum)
{
if (! ieee_require_atn65 (info, pp, &name, &namlen))
return FALSE;
}
/* This is emitted for method functions, but I don't think we
care very much. It might help if it told us useful
information like the class with which this function is
associated, but it doesn't, so it isn't helpful. */
}
break;
case 'B':
if (! ieee_read_cxx_defaults (info, pp, count))
return FALSE;
break;
case 'z':
{
const char *name, *mangled, *cxx_class;
unsigned long namlen, mangledlen, classlen;
bfd_vma control;
/* Pointer to member. */
if (! ieee_require_atn65 (info, pp, &name, &namlen)
|| ! ieee_require_atn65 (info, pp, &mangled, &mangledlen)
|| ! ieee_require_atn65 (info, pp, &cxx_class, &classlen)
|| ! ieee_require_asn (info, pp, &control))
return FALSE;
/* FIXME: We should now track down name and change its type. */
}
break;
case 'R':
if (! ieee_read_reference (info, pp))
return FALSE;
break;
}
return TRUE;
}
/* Read a C++ class definition. This is a pmisc type 80 record of
category 'T'. */
static bfd_boolean
ieee_read_cxx_class (struct ieee_info *info, const bfd_byte **pp,
unsigned long count)
{
const bfd_byte *start;
bfd_vma cxx_class;
const char *tag;
unsigned long taglen;
struct ieee_tag *it;
void *dhandle;
debug_field *fields;
unsigned int field_count, field_alloc;
debug_baseclass *baseclasses;
unsigned int baseclasses_count, baseclasses_alloc;
const debug_field *structfields;
struct ieee_method
{
const char *name;
unsigned long namlen;
debug_method_variant *variants;
unsigned count;
unsigned int alloc;
} *methods;
unsigned int methods_count, methods_alloc;
debug_type vptrbase;
bfd_boolean ownvptr;
debug_method *dmethods;
start = *pp;
if (! ieee_require_asn (info, pp, &cxx_class))
return FALSE;
--count;
if (! ieee_require_atn65 (info, pp, &tag, &taglen))
return FALSE;
--count;
/* Find the C struct with this name. */
for (it = info->tags; it != NULL; it = it->next)
if (it->name[0] == tag[0]
&& strncmp (it->name, tag, taglen) == 0
&& strlen (it->name) == taglen)
break;
if (it == NULL)
{
ieee_error (info, start, _("undefined C++ object"));
return FALSE;
}
dhandle = info->dhandle;
fields = NULL;
field_count = 0;
field_alloc = 0;
baseclasses = NULL;
baseclasses_count = 0;
baseclasses_alloc = 0;
methods = NULL;
methods_count = 0;
methods_alloc = 0;
vptrbase = DEBUG_TYPE_NULL;
ownvptr = FALSE;
structfields = debug_get_fields (dhandle, it->type);
while (count > 0)
{
bfd_vma id;
const bfd_byte *spec_start;
spec_start = *pp;
if (! ieee_require_asn (info, pp, &id))
return FALSE;
--count;
switch (id)
{
default:
ieee_error (info, spec_start, _("unrecognized C++ object spec"));
return FALSE;
case 'b':
{
bfd_vma flags, cinline;
const char *base, *fieldname;
unsigned long baselen, fieldlen;
char *basecopy;
debug_type basetype;
bfd_vma bitpos;
bfd_boolean virtualp;
enum debug_visibility visibility;
debug_baseclass baseclass;
/* This represents a base or friend class. */
if (! ieee_require_asn (info, pp, &flags)
|| ! ieee_require_atn65 (info, pp, &base, &baselen)
|| ! ieee_require_asn (info, pp, &cinline)
|| ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen))
return FALSE;
count -= 4;
/* We have no way of recording friend information, so we
just ignore it. */
if ((flags & BASEFLAGS_FRIEND) != 0)
break;
/* I assume that either all of the members of the
baseclass are included in the object, starting at the
beginning of the object, or that none of them are
included. */
if ((fieldlen == 0) == (cinline == 0))
{
ieee_error (info, start, _("unsupported C++ object type"));
return FALSE;
}
basecopy = savestring (base, baselen);
basetype = debug_find_tagged_type (dhandle, basecopy,
DEBUG_KIND_ILLEGAL);
free (basecopy);
if (basetype == DEBUG_TYPE_NULL)
{
ieee_error (info, start, _("C++ base class not defined"));
return FALSE;
}
if (fieldlen == 0)
bitpos = 0;
else
{
const debug_field *pf;
if (structfields == NULL)
{
ieee_error (info, start, _("C++ object has no fields"));
return FALSE;
}
for (pf = structfields; *pf != DEBUG_FIELD_NULL; pf++)
{
const char *fname;
fname = debug_get_field_name (dhandle, *pf);
if (fname == NULL)
return FALSE;
if (fname[0] == fieldname[0]
&& strncmp (fname, fieldname, fieldlen) == 0
&& strlen (fname) == fieldlen)
break;
}
if (*pf == DEBUG_FIELD_NULL)
{
ieee_error (info, start,
_("C++ base class not found in container"));
return FALSE;
}
bitpos = debug_get_field_bitpos (dhandle, *pf);
}
if ((flags & BASEFLAGS_VIRTUAL) != 0)
virtualp = TRUE;
else
virtualp = FALSE;
if ((flags & BASEFLAGS_PRIVATE) != 0)
visibility = DEBUG_VISIBILITY_PRIVATE;
else
visibility = DEBUG_VISIBILITY_PUBLIC;
baseclass = debug_make_baseclass (dhandle, basetype, bitpos,
virtualp, visibility);
if (baseclass == DEBUG_BASECLASS_NULL)
return FALSE;
if (baseclasses_count + 1 >= baseclasses_alloc)
{
baseclasses_alloc += 10;
baseclasses = ((debug_baseclass *)
xrealloc (baseclasses,
(baseclasses_alloc
* sizeof *baseclasses)));
}
baseclasses[baseclasses_count] = baseclass;
++baseclasses_count;
baseclasses[baseclasses_count] = DEBUG_BASECLASS_NULL;
}
break;
case 'd':
{
bfd_vma flags;
const char *fieldname, *mangledname;
unsigned long fieldlen, mangledlen;
char *fieldcopy;
bfd_boolean staticp;
debug_type ftype;
const debug_field *pf = NULL;
enum debug_visibility visibility;
debug_field field;
/* This represents a data member. */
if (! ieee_require_asn (info, pp, &flags)
|| ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen)
|| ! ieee_require_atn65 (info, pp, &mangledname, &mangledlen))
return FALSE;
count -= 3;
fieldcopy = savestring (fieldname, fieldlen);
staticp = (flags & CXXFLAGS_STATIC) != 0 ? TRUE : FALSE;
if (staticp)
{
struct ieee_var *pv, *pvend;
/* See if we can find a definition for this variable. */
pv = info->vars.vars;
pvend = pv + info->vars.alloc;
for (; pv < pvend; pv++)
if (pv->namlen == mangledlen
&& strncmp (pv->name, mangledname, mangledlen) == 0)
break;
if (pv < pvend)
ftype = pv->type;
else
{
/* This can happen if the variable is never used. */
ftype = ieee_builtin_type (info, start,
(unsigned int) builtin_void);
}
}
else
{
unsigned int findx;
if (structfields == NULL)
{
ieee_error (info, start, _("C++ object has no fields"));
return FALSE;
}
for (pf = structfields, findx = 0;
*pf != DEBUG_FIELD_NULL;
pf++, findx++)
{
const char *fname;
fname = debug_get_field_name (dhandle, *pf);
if (fname == NULL)
return FALSE;
if (fname[0] == mangledname[0]
&& strncmp (fname, mangledname, mangledlen) == 0
&& strlen (fname) == mangledlen)
break;
}
if (*pf == DEBUG_FIELD_NULL)
{
ieee_error (info, start,
_("C++ data member not found in container"));