#include <stdio.h>
#include "bfd.h"
#include "bucomm.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "demangle.h"
#include "debug.h"
#include "budbg.h"
#include "filenames.h"
#include "aout/aout64.h"
#include "aout/stab_gnu.h"
#define XCOFF_TYPE_COUNT 34
struct stab_handle
{
bfd *abfd;
bfd_boolean sections;
asymbol **syms;
long symcount;
char *so_string;
bfd_vma so_value;
bfd_vma file_start_offset;
bfd_vma function_start_offset;
int gcc_compiled;
bfd_boolean n_opt_found;
char *main_filename;
struct bincl_file *bincl_stack;
struct bincl_file *bincl_list;
bfd_boolean within_function;
bfd_vma function_end;
int block_depth;
struct stab_pending_var *pending;
unsigned int files;
struct stab_types **file_types;
debug_type xcoff_types[XCOFF_TYPE_COUNT];
struct stab_tag *tags;
bfd_boolean self_crossref;
};
struct stab_pending_var
{
struct stab_pending_var *next;
const char *name;
debug_type type;
enum debug_var_kind kind;
bfd_vma val;
};
struct stab_types
{
struct stab_types *next;
#define STAB_TYPES_SLOTS (16)
debug_type types[STAB_TYPES_SLOTS];
};
struct stab_tag
{
struct stab_tag *next;
const char *name;
enum debug_type_kind kind;
debug_type slot;
debug_type type;
};
static char *savestring (const char *, int);
static bfd_vma parse_number (const char **, bfd_boolean *);
static void bad_stab (const char *);
static void warn_stab (const char *, const char *);
static bfd_boolean parse_stab_string
(void *, struct stab_handle *, int, int, bfd_vma, const char *);
static debug_type parse_stab_type
(void *, struct stab_handle *, const char *, const char **, debug_type **);
static bfd_boolean parse_stab_type_number (const char **, int *);
static debug_type parse_stab_range_type
(void *, struct stab_handle *, const char *, const char **, const int *);
static debug_type parse_stab_sun_builtin_type (void *, const char **);
static debug_type parse_stab_sun_floating_type (void *, const char **);
static debug_type parse_stab_enum_type (void *, const char **);
static debug_type parse_stab_struct_type
(void *, struct stab_handle *, const char *, const char **,
bfd_boolean, const int *);
static bfd_boolean parse_stab_baseclasses
(void *, struct stab_handle *, const char **, debug_baseclass **);
static bfd_boolean parse_stab_struct_fields
(void *, struct stab_handle *, const char **, debug_field **, bfd_boolean *);
static bfd_boolean parse_stab_cpp_abbrev
(void *, struct stab_handle *, const char **, debug_field *);
static bfd_boolean parse_stab_one_struct_field
(void *, struct stab_handle *, const char **, const char *,
debug_field *, bfd_boolean *);
static bfd_boolean parse_stab_members
(void *, struct stab_handle *, const char *, const char **, const int *,
debug_method **);
static debug_type parse_stab_argtypes
(void *, struct stab_handle *, debug_type, const char *, const char *,
debug_type, const char *, bfd_boolean, bfd_boolean, const char **);
static bfd_boolean parse_stab_tilde_field
(void *, struct stab_handle *, const char **, const int *, debug_type *,
bfd_boolean *);
static debug_type parse_stab_array_type
(void *, struct stab_handle *, const char **, bfd_boolean);
static void push_bincl (struct stab_handle *, const char *, bfd_vma);
static const char *pop_bincl (struct stab_handle *);
static bfd_boolean find_excl (struct stab_handle *, const char *, bfd_vma);
static bfd_boolean stab_record_variable
(void *, struct stab_handle *, const char *, debug_type,
enum debug_var_kind, bfd_vma);
static bfd_boolean stab_emit_pending_vars (void *, struct stab_handle *);
static debug_type *stab_find_slot (struct stab_handle *, const int *);
static debug_type stab_find_type (void *, struct stab_handle *, const int *);
static bfd_boolean stab_record_type
(void *, struct stab_handle *, const int *, debug_type);
static debug_type stab_xcoff_builtin_type
(void *, struct stab_handle *, int);
static debug_type stab_find_tagged_type
(void *, struct stab_handle *, const char *, int, enum debug_type_kind);
static debug_type *stab_demangle_argtypes
(void *, struct stab_handle *, const char *, bfd_boolean *, unsigned int);
static debug_type *stab_demangle_v3_argtypes
(void *, struct stab_handle *, const char *, bfd_boolean *);
static debug_type *stab_demangle_v3_arglist
(void *, struct stab_handle *, struct demangle_component *, bfd_boolean *);
static debug_type stab_demangle_v3_arg
(void *, struct stab_handle *, struct demangle_component *, debug_type,
bfd_boolean *);
static char *
savestring (const char *start, int len)
{
char *ret;
ret = (char *) xmalloc (len + 1);
memcpy (ret, start, len);
ret[len] = '\0';
return ret;
}
static bfd_vma
parse_number (const char **pp, bfd_boolean *poverflow)
{
unsigned long ul;
const char *orig;
if (poverflow != NULL)
*poverflow = FALSE;
orig = *pp;
errno = 0;
ul = strtoul (*pp, (char **) pp, 0);
if (ul + 1 != 0 || errno == 0)
{
if (*orig == '-')
return (bfd_vma) (bfd_signed_vma) (long) ul;
return (bfd_vma) ul;
}
if (sizeof (bfd_vma) > sizeof (unsigned long))
{
const char *p;
bfd_boolean neg;
int base;
bfd_vma over, lastdig;
bfd_boolean overflow;
bfd_vma v;
p = orig;
neg = FALSE;
if (*p == '+')
++p;
else if (*p == '-')
{
neg = TRUE;
++p;
}
base = 10;
if (*p == '0')
{
if (p[1] == 'x' || p[1] == 'X')
{
base = 16;
p += 2;
}
else
{
base = 8;
++p;
}
}
over = ((bfd_vma) (bfd_signed_vma) -1) / (bfd_vma) base;
lastdig = ((bfd_vma) (bfd_signed_vma) -1) % (bfd_vma) base;
overflow = FALSE;
v = 0;
while (1)
{
int d;
d = *p++;
if (ISDIGIT (d))
d -= '0';
else if (ISUPPER (d))
d -= 'A';
else if (ISLOWER (d))
d -= 'a';
else
break;
if (d >= base)
break;
if (v > over || (v == over && (bfd_vma) d > lastdig))
{
overflow = TRUE;
break;
}
}
if (! overflow)
{
if (neg)
v = - v;
return v;
}
}
if (poverflow != NULL)
*poverflow = TRUE;
else
warn_stab (orig, _("numeric overflow"));
return 0;
}
static void
bad_stab (const char *p)
{
fprintf (stderr, _("Bad stab: %s\n"), p);
}
static void
warn_stab (const char *p, const char *err)
{
fprintf (stderr, _("Warning: %s: %s\n"), err, p);
}
void *
start_stab (void *dhandle ATTRIBUTE_UNUSED, bfd *abfd, bfd_boolean sections,
asymbol **syms, long symcount)
{
struct stab_handle *ret;
ret = (struct stab_handle *) xmalloc (sizeof *ret);
memset (ret, 0, sizeof *ret);
ret->abfd = abfd;
ret->sections = sections;
ret->syms = syms;
ret->symcount = symcount;
ret->files = 1;
ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types);
ret->file_types[0] = NULL;
ret->function_end = (bfd_vma) -1;
return (void *) ret;
}
bfd_boolean
finish_stab (void *dhandle, void *handle)
{
struct stab_handle *info = (struct stab_handle *) handle;
struct stab_tag *st;
if (info->within_function)
{
if (! stab_emit_pending_vars (dhandle, info)
|| ! debug_end_function (dhandle, info->function_end))
return FALSE;
info->within_function = FALSE;
info->function_end = (bfd_vma) -1;
}
for (st = info->tags; st != NULL; st = st->next)
{
enum debug_type_kind kind;
kind = st->kind;
if (kind == DEBUG_KIND_ILLEGAL)
kind = DEBUG_KIND_STRUCT;
st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind);
if (st->slot == DEBUG_TYPE_NULL)
return FALSE;
}
return TRUE;
}
bfd_boolean
parse_stab (void *dhandle, void *handle, int type, int desc, bfd_vma value,
const char *string)
{
struct stab_handle *info = (struct stab_handle *) handle;
if (info->so_string != NULL
&& (type != N_SO || *string == '\0' || value != info->so_value))
{
if (! debug_set_filename (dhandle, info->so_string))
return FALSE;
info->main_filename = info->so_string;
info->gcc_compiled = 0;
info->n_opt_found = FALSE;
if (! info->sections)
info->file_start_offset = info->so_value;
info->files = 1;
info->file_types = ((struct stab_types **)
xmalloc (sizeof *info->file_types));
info->file_types[0] = NULL;
info->so_string = NULL;
}
switch (type)
{
case N_FN:
case N_FN_SEQ:
break;
case N_LBRAC:
if (info->n_opt_found && desc == 1)
break;
if (! info->within_function)
{
fprintf (stderr, _("N_LBRAC not within function\n"));
return FALSE;
}
if (! debug_start_block (dhandle,
(value
+ info->file_start_offset
+ info->function_start_offset)))
return FALSE;
if (! stab_emit_pending_vars (dhandle, info))
return FALSE;
++info->block_depth;
break;
case N_RBRAC:
if (info->n_opt_found && desc == 1)
break;
if (! stab_emit_pending_vars (dhandle, info))
return FALSE;
if (! debug_end_block (dhandle,
(value
+ info->file_start_offset
+ info->function_start_offset)))
return FALSE;
--info->block_depth;
if (info->block_depth < 0)
{
fprintf (stderr, _("Too many N_RBRACs\n"));
return FALSE;
}
break;
case N_SO:
if (info->within_function)
{
bfd_vma endval;
endval = value;
if (*string != '\0'
&& info->function_end != (bfd_vma) -1
&& info->function_end < endval)
endval = info->function_end;
if (! stab_emit_pending_vars (dhandle, info)
|| ! debug_end_function (dhandle, endval))
return FALSE;
info->within_function = FALSE;
info->function_end = (bfd_vma) -1;
}
if (*string == '\0')
return TRUE;
if (info->so_string == NULL)
info->so_string = xstrdup (string);
else
{
char *f;
f = info->so_string;
if (IS_ABSOLUTE_PATH (string))
info->so_string = xstrdup (string);
else
info->so_string = concat (info->so_string, string,
(const char *) NULL);
free (f);
}
info->so_value = value;
break;
case N_SOL:
if (! debug_start_source (dhandle, string))
return FALSE;
break;
case N_BINCL:
push_bincl (info, string, value);
if (! debug_start_source (dhandle, string))
return FALSE;
break;
case N_EINCL:
if (! debug_start_source (dhandle, pop_bincl (info)))
return FALSE;
break;
case N_EXCL:
if (! find_excl (info, string, value))
return FALSE;
break;
case N_SLINE:
if (! debug_record_line (dhandle, desc,
value + (info->within_function
? info->function_start_offset : 0)))
return FALSE;
break;
case N_BCOMM:
if (! debug_start_common_block (dhandle, string))
return FALSE;
break;
case N_ECOMM:
if (! debug_end_common_block (dhandle, string))
return FALSE;
break;
case N_FUN:
if (*string == '\0')
{
if (info->within_function)
{
if (info->sections)
value += info->function_start_offset;
if (! stab_emit_pending_vars (dhandle, info)
|| ! debug_end_function (dhandle, value))
return FALSE;
info->within_function = FALSE;
info->function_end = (bfd_vma) -1;
}
break;
}
if (info->within_function
&& (info->function_end == (bfd_vma) -1
|| value < info->function_end))
info->function_end = value;
default:
{
const char *colon;
colon = strchr (string, ':');
if (colon != NULL
&& (colon[1] == 'f' || colon[1] == 'F'))
{
if (info->within_function)
{
bfd_vma endval;
endval = value;
if (info->function_end != (bfd_vma) -1
&& info->function_end < endval)
endval = info->function_end;
if (! stab_emit_pending_vars (dhandle, info)
|| ! debug_end_function (dhandle, endval))
return FALSE;
info->function_end = (bfd_vma) -1;
}
if (info->sections)
info->function_start_offset = value;
info->within_function = TRUE;
}
if (! parse_stab_string (dhandle, info, type, desc, value, string))
return FALSE;
}
break;
case N_OPT:
if (string != NULL && strcmp (string, "gcc2_compiled.") == 0)
info->gcc_compiled = 2;
else if (string != NULL && strcmp (string, "gcc_compiled.") == 0)
info->gcc_compiled = 1;
else
info->n_opt_found = TRUE;
break;
case N_OBJ:
case N_ENDM:
case N_MAIN:
case N_WARNING:
break;
}
return TRUE;
}
static bfd_boolean
parse_stab_string (void *dhandle, struct stab_handle *info, int stabtype,
int desc, bfd_vma value, const char *string)
{
const char *p;
char *name;
int type;
debug_type dtype;
bfd_boolean synonym;
bfd_boolean self_crossref;
unsigned int lineno;
debug_type *slot;
p = strchr (string, ':');
if (p == NULL)
return TRUE;
while (p[1] == ':')
{
p += 2;
p = strchr (p, ':');
if (p == NULL)
{
bad_stab (string);
return FALSE;
}
}
if (info->gcc_compiled >= 2)
lineno = desc;
else
lineno = 0;
name = NULL;
if (string[0] == '$')
{
switch (string[1])
{
case 't':
name = "this";
break;
case 'v':
break;
case 'e':
name = "eh_throw";
break;
case '_':
break;
case 'X':
break;
default:
warn_stab (string, _("unknown C++ encoded name"));
break;
}
}
if (name == NULL)
{
if (p == string || (string[0] == ' ' && p == string + 1))
name = NULL;
else
name = savestring (string, p - string);
}
++p;
if (ISDIGIT (*p) || *p == '(' || *p == '-')
type = 'l';
else
type = *p++;
switch (type)
{
case 'c':
if (*p != '=')
{
bad_stab (string);
return FALSE;
}
++p;
switch (*p++)
{
case 'r':
if (! debug_record_float_const (dhandle, name, atof (p)))
return FALSE;
break;
case 'i':
if (! debug_record_int_const (dhandle, name, atoi (p)))
return FALSE;
break;
case 'e':
dtype = parse_stab_type (dhandle, info, (const char *) NULL,
&p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (*p != ',')
{
bad_stab (string);
return FALSE;
}
if (! debug_record_typed_const (dhandle, name, dtype, atoi (p)))
return FALSE;
break;
default:
bad_stab (string);
return FALSE;
}
break;
case 'C':
dtype = parse_stab_type (dhandle, info, (const char *) NULL,
&p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_label (dhandle, name, dtype, value))
return FALSE;
break;
case 'f':
case 'F':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_function (dhandle, name, dtype, type == 'F', value))
return FALSE;
while (*p == ';')
{
++p;
if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL)
== DEBUG_TYPE_NULL)
return FALSE;
}
break;
case 'G':
{
char leading;
long c;
asymbol **ps;
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
leading = bfd_get_symbol_leading_char (info->abfd);
for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
{
const char *n;
n = bfd_asymbol_name (*ps);
if (leading != '\0' && *n == leading)
++n;
if (*n == *name && strcmp (n, name) == 0)
break;
}
if (c > 0)
value = bfd_asymbol_value (*ps);
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
value))
return FALSE;
}
break;
case 'l':
case 's':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
value))
return FALSE;
break;
case 'p':
if (*p != 'F')
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
else
{
++p;
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype != DEBUG_TYPE_NULL)
{
debug_type ftype;
ftype = debug_make_function_type (dhandle, dtype,
(debug_type *) NULL, FALSE);
dtype = debug_make_pointer_type (dhandle, ftype);
}
}
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_STACK,
value))
return FALSE;
break;
case 'P':
if (stabtype == N_FUN)
{
while (*p == ';')
{
++p;
if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL)
== DEBUG_TYPE_NULL)
return FALSE;
}
break;
}
case 'R':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG,
value))
return FALSE;
break;
case 'r':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER,
value))
return FALSE;
break;
case 'S':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC,
value))
return FALSE;
break;
case 't':
dtype = parse_stab_type (dhandle, info, name, &p, &slot);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (name == NULL)
{
return TRUE;
}
dtype = debug_name_type (dhandle, name, dtype);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (slot != NULL)
*slot = dtype;
break;
case 'T':
if (*p != 't')
{
synonym = FALSE;
}
else
{
synonym = TRUE;
++p;
}
dtype = parse_stab_type (dhandle, info, name, &p, &slot);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (name == NULL)
return TRUE;
self_crossref = info->self_crossref;
dtype = debug_tag_type (dhandle, name, dtype);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (slot != NULL)
*slot = dtype;
if (! self_crossref)
{
register struct stab_tag **pst;
for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next)
{
if ((*pst)->name[0] == name[0]
&& strcmp ((*pst)->name, name) == 0)
{
(*pst)->slot = dtype;
*pst = (*pst)->next;
break;
}
}
}
if (synonym)
{
dtype = debug_name_type (dhandle, name, dtype);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (slot != NULL)
*slot = dtype;
}
break;
case 'V':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! stab_record_variable (dhandle, info, name, dtype,
DEBUG_LOCAL_STATIC, value))
return FALSE;
break;
case 'v':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE,
value))
return FALSE;
break;
case 'a':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG,
value))
return FALSE;
break;
case 'X':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
value))
return FALSE;
break;
default:
bad_stab (string);
return FALSE;
}
return TRUE;
}
static debug_type
parse_stab_type (void *dhandle, struct stab_handle *info, const char *typename, const char **pp, debug_type **slotp)
{
const char *orig;
int typenums[2];
int size;
bfd_boolean stringp;
int descriptor;
debug_type dtype;
if (slotp != NULL)
*slotp = NULL;
orig = *pp;
size = -1;
stringp = FALSE;
info->self_crossref = FALSE;
if (! ISDIGIT (**pp) && **pp != '(' && **pp != '-')
{
typenums[0] = typenums[1] = -1;
}
else
{
if (! parse_stab_type_number (pp, typenums))
return DEBUG_TYPE_NULL;
if (**pp != '=')
return stab_find_type (dhandle, info, typenums);
if (slotp != NULL && typenums[0] >= 0 && typenums[1] >= 0)
*slotp = stab_find_slot (info, typenums);
++*pp;
while (**pp == '@')
{
const char *p = *pp + 1;
const char *attr;
if (ISDIGIT (*p) || *p == '(' || *p == '-')
break;
attr = p;
for (; *p != ';'; ++p)
{
if (*p == '\0')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
}
*pp = p + 1;
switch (*attr)
{
case 's':
size = atoi (attr + 1);
size /= 8;
if (size <= 0)
size = -1;
break;
case 'S':
stringp = TRUE;
break;
default:
break;
}
}
}
descriptor = **pp;
++*pp;
switch (descriptor)
{
case 'x':
{
enum debug_type_kind code;
const char *q1, *q2, *p;
switch (**pp)
{
case 's':
code = DEBUG_KIND_STRUCT;
break;
case 'u':
code = DEBUG_KIND_UNION;
break;
case 'e':
code = DEBUG_KIND_ENUM;
break;
default:
warn_stab (orig, _("unrecognized cross reference type"));
code = DEBUG_KIND_STRUCT;
break;
}
++*pp;
q1 = strchr (*pp, '<');
p = strchr (*pp, ':');
if (p == NULL)
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
if (q1 != NULL && p > q1 && p[1] == ':')
{
int nest = 0;
for (q2 = q1; *q2 != '\0'; ++q2)
{
if (*q2 == '<')
++nest;
else if (*q2 == '>')
--nest;
else if (*q2 == ':' && nest == 0)
break;
}
p = q2;
if (*p != ':')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
}
if (typename != NULL
&& strncmp (typename, *pp, p - *pp) == 0
&& typename[p - *pp] == '\0')
info->self_crossref = TRUE;
dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code);
*pp = p + 1;
}
break;
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '(':
{
const char *hold;
int xtypenums[2];
(*pp)--;
hold = *pp;
if (! parse_stab_type_number (pp, xtypenums))
return DEBUG_TYPE_NULL;
if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
{
dtype = debug_make_void_type (dhandle);
}
else
{
*pp = hold;
dtype = parse_stab_type (dhandle, info, (const char *) NULL,
pp, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
if (typenums[0] != -1)
{
if (! stab_record_type (dhandle, info, typenums, dtype))
return DEBUG_TYPE_NULL;
}
break;
}
case '*':
dtype = debug_make_pointer_type (dhandle,
parse_stab_type (dhandle, info,
(const char *) NULL,
pp,
(debug_type **) NULL));
break;
case '&':
dtype = (debug_make_reference_type
(dhandle,
parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL)));
break;
case 'f':
dtype = (debug_make_function_type
(dhandle,
parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL),
(debug_type *) NULL, FALSE));
break;
case 'k':
dtype = debug_make_const_type (dhandle,
parse_stab_type (dhandle, info,
(const char *) NULL,
pp,
(debug_type **) NULL));
break;
case 'B':
dtype = (debug_make_volatile_type
(dhandle,
parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL)));
break;
case '@':
{
debug_type domain;
debug_type memtype;
domain = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
if (domain == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (**pp != ',')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
if (memtype == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
dtype = debug_make_offset_type (dhandle, domain, memtype);
}
break;
case '#':
if (**pp == '#')
{
debug_type return_type;
++*pp;
return_type = parse_stab_type (dhandle, info, (const char *) NULL,
pp, (debug_type **) NULL);
if (return_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
dtype = debug_make_method_type (dhandle, return_type,
DEBUG_TYPE_NULL,
(debug_type *) NULL, FALSE);
}
else
{
debug_type domain;
debug_type return_type;
debug_type *args;
unsigned int n;
unsigned int alloc;
bfd_boolean varargs;
domain = parse_stab_type (dhandle, info, (const char *) NULL,
pp, (debug_type **) NULL);
if (domain == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (**pp != ',')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
return_type = parse_stab_type (dhandle, info, (const char *) NULL,
pp, (debug_type **) NULL);
if (return_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
alloc = 10;
args = (debug_type *) xmalloc (alloc * sizeof *args);
n = 0;
while (**pp != ';')
{
if (**pp != ',')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
if (n + 1 >= alloc)
{
alloc += 10;
args = ((debug_type *)
xrealloc (args, alloc * sizeof *args));
}
args[n] = parse_stab_type (dhandle, info, (const char *) NULL,
pp, (debug_type **) NULL);
if (args[n] == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
++n;
}
++*pp;
if (n == 0
|| debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID)
varargs = TRUE;
else
{
--n;
varargs = FALSE;
}
args[n] = DEBUG_TYPE_NULL;
dtype = debug_make_method_type (dhandle, return_type, domain, args,
varargs);
}
break;
case 'r':
dtype = parse_stab_range_type (dhandle, info, typename, pp, typenums);
break;
case 'b':
dtype = parse_stab_sun_builtin_type (dhandle, pp);
break;
case 'R':
dtype = parse_stab_sun_floating_type (dhandle, pp);
break;
case 'e':
dtype = parse_stab_enum_type (dhandle, pp);
break;
case 's':
case 'u':
dtype = parse_stab_struct_type (dhandle, info, typename, pp,
descriptor == 's', typenums);
break;
case 'a':
if (**pp != 'r')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
dtype = parse_stab_array_type (dhandle, info, pp, stringp);
break;
case 'S':
dtype = debug_make_set_type (dhandle,
parse_stab_type (dhandle, info,
(const char *) NULL,
pp,
(debug_type **) NULL),
stringp);
break;
default:
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
if (dtype == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (typenums[0] != -1)
{
if (! stab_record_type (dhandle, info, typenums, dtype))
return DEBUG_TYPE_NULL;
}
if (size != -1)
{
if (! debug_record_type_size (dhandle, dtype, (unsigned int) size))
return DEBUG_TYPE_NULL;
}
return dtype;
}
static bfd_boolean
parse_stab_type_number (const char **pp, int *typenums)
{
const char *orig;
orig = *pp;
if (**pp != '(')
{
typenums[0] = 0;
typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL);
}
else
{
++*pp;
typenums[0] = (int) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return FALSE;
}
++*pp;
typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ')')
{
bad_stab (orig);
return FALSE;
}
++*pp;
}
return TRUE;
}
static debug_type
parse_stab_range_type (void *dhandle, struct stab_handle *info, const char *typename, const char **pp, const int *typenums)
{
const char *orig;
int rangenums[2];
bfd_boolean self_subrange;
debug_type index_type;
const char *s2, *s3;
bfd_signed_vma n2, n3;
bfd_boolean ov2, ov3;
orig = *pp;
index_type = DEBUG_TYPE_NULL;
if (! parse_stab_type_number (pp, rangenums))
return DEBUG_TYPE_NULL;
self_subrange = (rangenums[0] == typenums[0]
&& rangenums[1] == typenums[1]);
if (**pp == '=')
{
*pp = orig;
index_type = parse_stab_type (dhandle, info, (const char *) NULL,
pp, (debug_type **) NULL);
if (index_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
if (**pp == ';')
++*pp;
s2 = *pp;
n2 = parse_number (pp, &ov2);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
s3 = *pp;
n3 = parse_number (pp, &ov3);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
if (ov2 || ov3)
{
#define LLLOW "01000000000000000000000;"
#define LLHIGH "0777777777777777777777;"
#define ULLHIGH "01777777777777777777777;"
if (index_type == DEBUG_TYPE_NULL)
{
if (strncmp (s2, LLLOW, sizeof LLLOW - 1) == 0
&& strncmp (s3, LLHIGH, sizeof LLHIGH - 1) == 0)
return debug_make_int_type (dhandle, 8, FALSE);
if (! ov2
&& n2 == 0
&& strncmp (s3, ULLHIGH, sizeof ULLHIGH - 1) == 0)
return debug_make_int_type (dhandle, 8, TRUE);
}
warn_stab (orig, _("numeric overflow"));
}
if (index_type == DEBUG_TYPE_NULL)
{
if (self_subrange && n2 == 0 && n3 == 0)
return debug_make_void_type (dhandle);
if (self_subrange && n3 == 0 && n2 > 0)
return debug_make_complex_type (dhandle, n2);
if (n3 == 0 && n2 > 0)
return debug_make_float_type (dhandle, n2);
if (n2 == 0 && n3 == -1)
{
if (typename != NULL)
{
if (strcmp (typename, "long long int") == 0)
return debug_make_int_type (dhandle, 8, FALSE);
else if (strcmp (typename, "long long unsigned int") == 0)
return debug_make_int_type (dhandle, 8, TRUE);
}
return debug_make_int_type (dhandle, 4, TRUE);
}
if (self_subrange && n2 == 0 && n3 == 127)
return debug_make_int_type (dhandle, 1, FALSE);
if (n2 == 0)
{
if (n3 < 0)
return debug_make_int_type (dhandle, - n3, TRUE);
else if (n3 == 0xff)
return debug_make_int_type (dhandle, 1, TRUE);
else if (n3 == 0xffff)
return debug_make_int_type (dhandle, 2, TRUE);
else if (n3 == (bfd_signed_vma) 0xffffffff)
return debug_make_int_type (dhandle, 4, TRUE);
#ifdef BFD64
else if (n3 == ((((bfd_signed_vma) 0xffffffff) << 32) | 0xffffffff))
return debug_make_int_type (dhandle, 8, TRUE);
#endif
}
else if (n3 == 0
&& n2 < 0
&& (self_subrange || n2 == -8))
return debug_make_int_type (dhandle, - n2, TRUE);
else if (n2 == - n3 - 1 || n2 == n3 + 1)
{
if (n3 == 0x7f)
return debug_make_int_type (dhandle, 1, FALSE);
else if (n3 == 0x7fff)
return debug_make_int_type (dhandle, 2, FALSE);
else if (n3 == 0x7fffffff)
return debug_make_int_type (dhandle, 4, FALSE);
#ifdef BFD64
else if (n3 == ((((bfd_vma) 0x7fffffff) << 32) | 0xffffffff))
return debug_make_int_type (dhandle, 8, FALSE);
#endif
}
}
if (self_subrange)
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
index_type = stab_find_type (dhandle, info, rangenums);
if (index_type == DEBUG_TYPE_NULL)
{
warn_stab (orig, _("missing index type"));
index_type = debug_make_int_type (dhandle, 4, FALSE);
}
return debug_make_range_type (dhandle, index_type, n2, n3);
}
static debug_type
parse_stab_sun_builtin_type (void *dhandle, const char **pp)
{
const char *orig;
bfd_boolean unsignedp;
bfd_vma bits;
orig = *pp;
switch (**pp)
{
case 's':
unsignedp = FALSE;
break;
case 'u':
unsignedp = TRUE;
break;
default:
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
if (**pp == 'c')
++*pp;
(void) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
(void) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
bits = parse_number (pp, (bfd_boolean *) NULL);
if (**pp == ';')
++*pp;
if (bits == 0)
return debug_make_void_type (dhandle);
return debug_make_int_type (dhandle, bits / 8, unsignedp);
}
static debug_type
parse_stab_sun_floating_type (void *dhandle, const char **pp)
{
const char *orig;
bfd_vma details;
bfd_vma bytes;
orig = *pp;
details = parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
bytes = parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
if (details == NF_COMPLEX
|| details == NF_COMPLEX16
|| details == NF_COMPLEX32)
return debug_make_complex_type (dhandle, bytes);
return debug_make_float_type (dhandle, bytes);
}
static debug_type
parse_stab_enum_type (void *dhandle, const char **pp)
{
const char *orig;
const char **names;
bfd_signed_vma *values;
unsigned int n;
unsigned int alloc;
orig = *pp;
if (**pp == '-')
{
while (**pp != ':')
++*pp;
++*pp;
}
alloc = 10;
names = (const char **) xmalloc (alloc * sizeof *names);
values = (bfd_signed_vma *) xmalloc (alloc * sizeof *values);
n = 0;
while (**pp != '\0' && **pp != ';' && **pp != ',')
{
const char *p;
char *name;
bfd_signed_vma val;
p = *pp;
while (*p != ':')
++p;
name = savestring (*pp, p - *pp);
*pp = p + 1;
val = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
if (n + 1 >= alloc)
{
alloc += 10;
names = ((const char **)
xrealloc (names, alloc * sizeof *names));
values = ((bfd_signed_vma *)
xrealloc (values, alloc * sizeof *values));
}
names[n] = name;
values[n] = val;
++n;
}
names[n] = NULL;
values[n] = 0;
if (**pp == ';')
++*pp;
return debug_make_enum_type (dhandle, names, values);
}
static debug_type
parse_stab_struct_type (void *dhandle, struct stab_handle *info,
const char *tagname, const char **pp,
bfd_boolean structp, const int *typenums)
{
const char *orig;
bfd_vma size;
debug_baseclass *baseclasses;
debug_field *fields;
bfd_boolean statics;
debug_method *methods;
debug_type vptrbase;
bfd_boolean ownvptr;
orig = *pp;
size = parse_number (pp, (bfd_boolean *) NULL);
if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses)
|| ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics)
|| ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods)
|| ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase,
&ownvptr))
return DEBUG_TYPE_NULL;
if (! statics
&& baseclasses == NULL
&& methods == NULL
&& vptrbase == DEBUG_TYPE_NULL
&& ! ownvptr)
return debug_make_struct_type (dhandle, structp, size, fields);
return debug_make_object_type (dhandle, structp, size, fields, baseclasses,
methods, vptrbase, ownvptr);
}
static bfd_boolean
parse_stab_baseclasses (void *dhandle, struct stab_handle *info,
const char **pp, debug_baseclass **retp)
{
const char *orig;
unsigned int c, i;
debug_baseclass *classes;
*retp = NULL;
orig = *pp;
if (**pp != '!')
{
return TRUE;
}
++*pp;
c = (unsigned int) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return FALSE;
}
++*pp;
classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp));
for (i = 0; i < c; i++)
{
bfd_boolean virtual;
enum debug_visibility visibility;
bfd_vma bitpos;
debug_type type;
switch (**pp)
{
case '0':
virtual = FALSE;
break;
case '1':
virtual = TRUE;
break;
default:
warn_stab (orig, _("unknown virtual character for baseclass"));
virtual = FALSE;
break;
}
++*pp;
switch (**pp)
{
case '0':
visibility = DEBUG_VISIBILITY_PRIVATE;
break;
case '1':
visibility = DEBUG_VISIBILITY_PROTECTED;
break;
case '2':
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
default:
warn_stab (orig, _("unknown visibility character for baseclass"));
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
}
++*pp;
bitpos = parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return FALSE;
}
++*pp;
type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
return FALSE;
classes[i] = debug_make_baseclass (dhandle, type, bitpos, virtual,
visibility);
if (classes[i] == DEBUG_BASECLASS_NULL)
return FALSE;
if (**pp != ';')
return FALSE;
++*pp;
}
classes[i] = DEBUG_BASECLASS_NULL;
*retp = classes;
return TRUE;
}
static bfd_boolean
parse_stab_struct_fields (void *dhandle, struct stab_handle *info,
const char **pp, debug_field **retp,
bfd_boolean *staticsp)
{
const char *orig;
const char *p;
debug_field *fields;
unsigned int c;
unsigned int alloc;
*retp = NULL;
*staticsp = FALSE;
orig = *pp;
c = 0;
alloc = 10;
fields = (debug_field *) xmalloc (alloc * sizeof *fields);
while (**pp != ';')
{
p = *pp;
if (c + 1 >= alloc)
{
alloc += 10;
fields = ((debug_field *)
xrealloc (fields, alloc * sizeof *fields));
}
if ((*p == '$' || *p == '.') && p[1] != '_')
{
++*pp;
if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c))
return FALSE;
++c;
continue;
}
p = strchr (p, ':');
if (p == NULL)
{
bad_stab (orig);
return FALSE;
}
if (p[1] == ':')
break;
if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c,
staticsp))
return FALSE;
++c;
}
fields[c] = DEBUG_FIELD_NULL;
*retp = fields;
return TRUE;
}
static bfd_boolean
parse_stab_cpp_abbrev (void *dhandle, struct stab_handle *info,
const char **pp, debug_field *retp)
{
const char *orig;
int cpp_abbrev;
debug_type context;
const char *name;
const char *typename;
debug_type type;
bfd_vma bitpos;
*retp = DEBUG_FIELD_NULL;
orig = *pp;
if (**pp != 'v')
{
bad_stab (*pp);
return FALSE;
}
++*pp;
cpp_abbrev = **pp;
++*pp;
context = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
if (context == DEBUG_TYPE_NULL)
return FALSE;
switch (cpp_abbrev)
{
case 'f':
name = "_vptr$";
break;
case 'b':
typename = debug_get_type_name (dhandle, context);
if (typename == NULL)
{
warn_stab (orig, _("unnamed $vb type"));
typename = "FOO";
}
name = concat ("_vb$", typename, (const char *) NULL);
break;
default:
warn_stab (orig, _("unrecognized C++ abbreviation"));
name = "INVALID_CPLUSPLUS_ABBREV";
break;
}
if (**pp != ':')
{
bad_stab (orig);
return FALSE;
}
++*pp;
type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
if (**pp != ',')
{
bad_stab (orig);
return FALSE;
}
++*pp;
bitpos = parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return FALSE;
}
++*pp;
*retp = debug_make_field (dhandle, name, type, bitpos, 0,
DEBUG_VISIBILITY_PRIVATE);
if (*retp == DEBUG_FIELD_NULL)
return FALSE;
return TRUE;
}
static bfd_boolean
parse_stab_one_struct_field (void *dhandle, struct stab_handle *info,
const char **pp, const char *p,
debug_field *retp, bfd_boolean *staticsp)
{
const char *orig;
char *name;
enum debug_visibility visibility;
debug_type type;
bfd_vma bitpos;
bfd_vma bitsize;
orig = *pp;
name = savestring (*pp, p - *pp);
*pp = p + 1;
if (**pp != '/')
visibility = DEBUG_VISIBILITY_PUBLIC;
else
{
++*pp;
switch (**pp)
{
case '0':
visibility = DEBUG_VISIBILITY_PRIVATE;
break;
case '1':
visibility = DEBUG_VISIBILITY_PROTECTED;
break;
case '2':
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
default:
warn_stab (orig, _("unknown visibility character for field"));
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
}
++*pp;
}
type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
return FALSE;
if (**pp == ':')
{
char *varname;
++*pp;
p = strchr (*pp, ';');
if (p == NULL)
{
bad_stab (orig);
return FALSE;
}
varname = savestring (*pp, p - *pp);
*pp = p + 1;
*retp = debug_make_static_member (dhandle, name, type, varname,
visibility);
*staticsp = TRUE;
return TRUE;
}
if (**pp != ',')
{
bad_stab (orig);
return FALSE;
}
++*pp;
bitpos = parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ',')
{
bad_stab (orig);
return FALSE;
}
++*pp;
bitsize = parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return FALSE;
}
++*pp;
if (bitpos == 0 && bitsize == 0)
{
visibility = DEBUG_VISIBILITY_IGNORE;
}
*retp = debug_make_field (dhandle, name, type, bitpos, bitsize, visibility);
return TRUE;
}
static bfd_boolean
parse_stab_members (void *dhandle, struct stab_handle *info,
const char *tagname, const char **pp,
const int *typenums, debug_method **retp)
{
const char *orig;
debug_method *methods;
unsigned int c;
unsigned int alloc;
*retp = NULL;
orig = *pp;
alloc = 0;
methods = NULL;
c = 0;
while (**pp != ';')
{
const char *p;
char *name;
debug_method_variant *variants;
unsigned int cvars;
unsigned int allocvars;
debug_type look_ahead_type;
p = strchr (*pp, ':');
if (p == NULL || p[1] != ':')
break;
if ((*pp)[0] != 'o' || (*pp)[1] != 'p' || (*pp)[2] != '$')
{
name = savestring (*pp, p - *pp);
*pp = p + 2;
}
else
{
*pp = p + 2;
for (p = *pp; *p != '.' && *p != '\0'; p++)
;
if (*p != '.')
{
bad_stab (orig);
return FALSE;
}
name = savestring (*pp, p - *pp);
*pp = p + 1;
}
allocvars = 10;
variants = ((debug_method_variant *)
xmalloc (allocvars * sizeof *variants));
cvars = 0;
look_ahead_type = DEBUG_TYPE_NULL;
do
{
debug_type type;
bfd_boolean stub;
char *argtypes;
enum debug_visibility visibility;
bfd_boolean constp, volatilep, staticp;
bfd_vma voffset;
debug_type context;
const char *physname;
bfd_boolean varargs;
if (look_ahead_type != DEBUG_TYPE_NULL)
{
type = look_ahead_type;
look_ahead_type = DEBUG_TYPE_NULL;
}
else
{
type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
return FALSE;
if (**pp != ':')
{
bad_stab (orig);
return FALSE;
}
}
++*pp;
p = strchr (*pp, ';');
if (p == NULL)
{
bad_stab (orig);
return FALSE;
}
stub = FALSE;
if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD
&& debug_get_parameter_types (dhandle, type, &varargs) == NULL)
stub = TRUE;
argtypes = savestring (*pp, p - *pp);
*pp = p + 1;
switch (**pp)
{
case '0':
visibility = DEBUG_VISIBILITY_PRIVATE;
break;
case '1':
visibility = DEBUG_VISIBILITY_PROTECTED;
break;
default:
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
}
++*pp;
constp = FALSE;
volatilep = FALSE;
switch (**pp)
{
case 'A':
++*pp;
break;
case 'B':
constp = TRUE;
++*pp;
break;
case 'C':
volatilep = TRUE;
++*pp;
break;
case 'D':
constp = TRUE;
volatilep = TRUE;
++*pp;
break;
case '*':
case '?':
case '.':
break;
default:
warn_stab (orig, _("const/volatile indicator missing"));
break;
}
staticp = FALSE;
switch (**pp)
{
case '*':
++*pp;
voffset = parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return FALSE;
}
++*pp;
voffset &= 0x7fffffff;
if (**pp == ';' || *pp == '\0')
{
context = DEBUG_TYPE_NULL;
}
else
{
look_ahead_type = parse_stab_type (dhandle, info,
(const char *) NULL,
pp,
(debug_type **) NULL);
if (**pp == ':')
{
context = DEBUG_TYPE_NULL;
}
else
{
context = look_ahead_type;
look_ahead_type = DEBUG_TYPE_NULL;
if (**pp != ';')
{
bad_stab (orig);
return FALSE;
}
++*pp;
}
}
break;
case '?':
++*pp;
staticp = TRUE;
voffset = 0;
context = DEBUG_TYPE_NULL;
if (strncmp (argtypes, name, strlen (name)) != 0)
stub = TRUE;
break;
default:
warn_stab (orig, "member function type missing");
voffset = 0;
context = DEBUG_TYPE_NULL;
break;
case '.':
++*pp;
voffset = 0;
context = DEBUG_TYPE_NULL;
break;
}
if (! stub)
physname = argtypes;
else
{
debug_type class_type, return_type;
class_type = stab_find_type (dhandle, info, typenums);
if (class_type == DEBUG_TYPE_NULL)
return FALSE;
return_type = debug_get_return_type (dhandle, type);
if (return_type == DEBUG_TYPE_NULL)
{
bad_stab (orig);
return FALSE;
}
type = parse_stab_argtypes (dhandle, info, class_type, name,
tagname, return_type, argtypes,
constp, volatilep, &physname);
if (type == DEBUG_TYPE_NULL)
return FALSE;
}
if (cvars + 1 >= allocvars)
{
allocvars += 10;
variants = ((debug_method_variant *)
xrealloc (variants,
allocvars * sizeof *variants));
}
if (! staticp)
variants[cvars] = debug_make_method_variant (dhandle, physname,
type, visibility,
constp, volatilep,
voffset, context);
else
variants[cvars] = debug_make_static_method_variant (dhandle,
physname,
type,
visibility,
constp,
volatilep);
if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL)
return FALSE;
++cvars;
}
while (**pp != ';' && **pp != '\0');
variants[cvars] = DEBUG_METHOD_VARIANT_NULL;
if (**pp != '\0')
++*pp;
if (c + 1 >= alloc)
{
alloc += 10;
methods = ((debug_method *)
xrealloc (methods, alloc * sizeof *methods));
}
methods[c] = debug_make_method (dhandle, name, variants);
++c;
}
if (methods != NULL)
methods[c] = DEBUG_METHOD_NULL;
*retp = methods;
return TRUE;
}
static debug_type
parse_stab_argtypes (void *dhandle, struct stab_handle *info,
debug_type class_type, const char *fieldname,
const char *tagname, debug_type return_type,
const char *argtypes, bfd_boolean constp,
bfd_boolean volatilep, const char **pphysname)
{
bfd_boolean is_full_physname_constructor;
bfd_boolean is_constructor;
bfd_boolean is_destructor;
bfd_boolean is_v3;
debug_type *args;
bfd_boolean varargs;
unsigned int physname_len = 0;
is_full_physname_constructor = ((argtypes[0] == '_'
&& argtypes[1] == '_'
&& (ISDIGIT (argtypes[2])
|| argtypes[2] == 'Q'
|| argtypes[2] == 't'))
|| strncmp (argtypes, "__ct", 4) == 0);
is_constructor = (is_full_physname_constructor
|| (tagname != NULL
&& strcmp (fieldname, tagname) == 0));
is_destructor = ((argtypes[0] == '_'
&& (argtypes[1] == '$' || argtypes[1] == '.')
&& argtypes[2] == '_')
|| strncmp (argtypes, "__dt", 4) == 0);
is_v3 = argtypes[0] == '_' && argtypes[1] == 'Z';
if (is_destructor || is_full_physname_constructor || is_v3)
*pphysname = argtypes;
else
{
unsigned int len;
const char *const_prefix;
const char *volatile_prefix;
char buf[20];
unsigned int mangled_name_len;
char *physname;
len = tagname == NULL ? 0 : strlen (tagname);
const_prefix = constp ? "C" : "";
volatile_prefix = volatilep ? "V" : "";
if (len == 0)
sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
else if (tagname != NULL && strchr (tagname, '<') != NULL)
{
sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
tagname = NULL;
len = 0;
}
else
sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len);
mangled_name_len = ((is_constructor ? 0 : strlen (fieldname))
+ strlen (buf)
+ len
+ strlen (argtypes)
+ 1);
if (fieldname[0] == 'o'
&& fieldname[1] == 'p'
&& (fieldname[2] == '$' || fieldname[2] == '.'))
{
const char *opname;
opname = cplus_mangle_opname (fieldname + 3, 0);
if (opname == NULL)
{
fprintf (stderr, _("No mangling for \"%s\"\n"), fieldname);
return DEBUG_TYPE_NULL;
}
mangled_name_len += strlen (opname);
physname = (char *) xmalloc (mangled_name_len);
strncpy (physname, fieldname, 3);
strcpy (physname + 3, opname);
}
else
{
physname = (char *) xmalloc (mangled_name_len);
if (is_constructor)
physname[0] = '\0';
else
strcpy (physname, fieldname);
}
physname_len = strlen (physname);
strcat (physname, buf);
if (tagname != NULL)
strcat (physname, tagname);
strcat (physname, argtypes);
*pphysname = physname;
}
if (*argtypes == '\0' || is_destructor)
{
args = (debug_type *) xmalloc (sizeof *args);
*args = NULL;
return debug_make_method_type (dhandle, return_type, class_type, args,
FALSE);
}
args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs, physname_len);
if (args == NULL)
return DEBUG_TYPE_NULL;
return debug_make_method_type (dhandle, return_type, class_type, args,
varargs);
}
static bfd_boolean
parse_stab_tilde_field (void *dhandle, struct stab_handle *info,
const char **pp, const int *typenums,
debug_type *retvptrbase, bfd_boolean *retownvptr)
{
const char *orig;
const char *hold;
int vtypenums[2];
*retvptrbase = DEBUG_TYPE_NULL;
*retownvptr = FALSE;
orig = *pp;
if (**pp == ';')
++*pp;
if (**pp != '~')
return TRUE;
++*pp;
if (**pp == '=' || **pp == '+' || **pp == '-')
{
++*pp;
}
if (**pp != '%')
return TRUE;
++*pp;
hold = *pp;
if (! parse_stab_type_number (pp, vtypenums))
return FALSE;
if (vtypenums[0] == typenums[0]
&& vtypenums[1] == typenums[1])
*retownvptr = TRUE;
else
{
debug_type vtype;
const char *p;
*pp = hold;
vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
for (p = *pp; *p != ';' && *p != '\0'; p++)
;
if (*p != ';')
{
bad_stab (orig);
return FALSE;
}
*retvptrbase = vtype;
*pp = p + 1;
}
return TRUE;
}
static debug_type
parse_stab_array_type (void *dhandle, struct stab_handle *info,
const char **pp, bfd_boolean stringp)
{
const char *orig;
const char *p;
int typenums[2];
debug_type index_type;
bfd_boolean adjustable;
bfd_signed_vma lower, upper;
debug_type element_type;
orig = *pp;
p = *pp;
if (! parse_stab_type_number (&p, typenums))
return DEBUG_TYPE_NULL;
if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=')
{
index_type = debug_find_named_type (dhandle, "int");
if (index_type == DEBUG_TYPE_NULL)
{
index_type = debug_make_int_type (dhandle, 4, FALSE);
if (index_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
*pp = p;
}
else
{
index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
}
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
adjustable = FALSE;
if (! ISDIGIT (**pp) && **pp != '-')
{
++*pp;
adjustable = TRUE;
}
lower = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
if (! ISDIGIT (**pp) && **pp != '-')
{
++*pp;
adjustable = TRUE;
}
upper = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
if (**pp != ';')
{
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
++*pp;
element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
(debug_type **) NULL);
if (element_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (adjustable)
{
lower = 0;
upper = -1;
}
return debug_make_array_type (dhandle, element_type, index_type, lower,
upper, stringp);
}
struct bincl_file
{
struct bincl_file *next;
struct bincl_file *next_stack;
const char *name;
bfd_vma hash;
unsigned int file;
struct stab_types *file_types;
};
static void
push_bincl (struct stab_handle *info, const char *name, bfd_vma hash)
{
struct bincl_file *n;
n = (struct bincl_file *) xmalloc (sizeof *n);
n->next = info->bincl_list;
n->next_stack = info->bincl_stack;
n->name = name;
n->hash = hash;
n->file = info->files;
n->file_types = NULL;
info->bincl_list = n;
info->bincl_stack = n;
++info->files;
info->file_types = ((struct stab_types **)
xrealloc (info->file_types,
(info->files
* sizeof *info->file_types)));
info->file_types[n->file] = NULL;
}
static const char *
pop_bincl (struct stab_handle *info)
{
struct bincl_file *o;
o = info->bincl_stack;
if (o == NULL)
return info->main_filename;
info->bincl_stack = o->next_stack;
o->file_types = info->file_types[o->file];
if (info->bincl_stack == NULL)
return info->main_filename;
return info->bincl_stack->name;
}
static bfd_boolean
find_excl (struct stab_handle *info, const char *name, bfd_vma hash)
{
struct bincl_file *l;
++info->files;
info->file_types = ((struct stab_types **)
xrealloc (info->file_types,
(info->files
* sizeof *info->file_types)));
for (l = info->bincl_list; l != NULL; l = l->next)
if (l->hash == hash && strcmp (l->name, name) == 0)
break;
if (l == NULL)
{
warn_stab (name, _("Undefined N_EXCL"));
info->file_types[info->files - 1] = NULL;
return TRUE;
}
info->file_types[info->files - 1] = l->file_types;
return TRUE;
}
static bfd_boolean
stab_record_variable (void *dhandle, struct stab_handle *info,
const char *name, debug_type type,
enum debug_var_kind kind, bfd_vma val)
{
struct stab_pending_var *v;
if ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC)
|| ! info->within_function
|| (info->gcc_compiled == 0 && info->n_opt_found))
return debug_record_variable (dhandle, name, type, kind, val);
v = (struct stab_pending_var *) xmalloc (sizeof *v);
memset (v, 0, sizeof *v);
v->next = info->pending;
v->name = name;
v->type = type;
v->kind = kind;
v->val = val;
info->pending = v;
return TRUE;
}
static bfd_boolean
stab_emit_pending_vars (void *dhandle, struct stab_handle *info)
{
struct stab_pending_var *v;
v = info->pending;
while (v != NULL)
{
struct stab_pending_var *next;
if (! debug_record_variable (dhandle, v->name, v->type, v->kind, v->val))
return FALSE;
next = v->next;
free (v);
v = next;
}
info->pending = NULL;
return TRUE;
}
static debug_type *
stab_find_slot (struct stab_handle *info, const int *typenums)
{
int filenum;
int index;
struct stab_types **ps;
filenum = typenums[0];
index = typenums[1];
if (filenum < 0 || (unsigned int) filenum >= info->files)
{
fprintf (stderr, _("Type file number %d out of range\n"), filenum);
return NULL;
}
if (index < 0)
{
fprintf (stderr, _("Type index number %d out of range\n"), index);
return NULL;
}
ps = info->file_types + filenum;
while (index >= STAB_TYPES_SLOTS)
{
if (*ps == NULL)
{
*ps = (struct stab_types *) xmalloc (sizeof **ps);
memset (*ps, 0, sizeof **ps);
}
ps = &(*ps)->next;
index -= STAB_TYPES_SLOTS;
}
if (*ps == NULL)
{
*ps = (struct stab_types *) xmalloc (sizeof **ps);
memset (*ps, 0, sizeof **ps);
}
return (*ps)->types + index;
}
static debug_type
stab_find_type (void *dhandle, struct stab_handle *info, const int *typenums)
{
debug_type *slot;
if (typenums[0] == 0 && typenums[1] < 0)
{
return stab_xcoff_builtin_type (dhandle, info, typenums[1]);
}
slot = stab_find_slot (info, typenums);
if (slot == NULL)
return DEBUG_TYPE_NULL;
if (*slot == DEBUG_TYPE_NULL)
return debug_make_indirect_type (dhandle, slot, (const char *) NULL);
return *slot;
}
static bfd_boolean
stab_record_type (void *dhandle ATTRIBUTE_UNUSED, struct stab_handle *info,
const int *typenums, debug_type type)
{
debug_type *slot;
slot = stab_find_slot (info, typenums);
if (slot == NULL)
return FALSE;
*slot = type;
return TRUE;
}
static debug_type
stab_xcoff_builtin_type (void *dhandle, struct stab_handle *info,
int typenum)
{
debug_type rettype;
const char *name;
if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT)
{
fprintf (stderr, _("Unrecognized XCOFF type %d\n"), typenum);
return DEBUG_TYPE_NULL;
}
if (info->xcoff_types[-typenum] != NULL)
return info->xcoff_types[-typenum];
switch (-typenum)
{
case 1:
name = "int";
rettype = debug_make_int_type (dhandle, 4, FALSE);
break;
case 2:
name = "char";
rettype = debug_make_int_type (dhandle, 1, FALSE);
break;
case 3:
name = "short";
rettype = debug_make_int_type (dhandle, 2, FALSE);
break;
case 4:
name = "long";
rettype = debug_make_int_type (dhandle, 4, FALSE);
break;
case 5:
name = "unsigned char";
rettype = debug_make_int_type (dhandle, 1, TRUE);
break;
case 6:
name = "signed char";
rettype = debug_make_int_type (dhandle, 1, FALSE);
break;
case 7:
name = "unsigned short";
rettype = debug_make_int_type (dhandle, 2, TRUE);
break;
case 8:
name = "unsigned int";
rettype = debug_make_int_type (dhandle, 4, TRUE);
break;
case 9:
name = "unsigned";
rettype = debug_make_int_type (dhandle, 4, TRUE);
case 10:
name = "unsigned long";
rettype = debug_make_int_type (dhandle, 4, TRUE);
break;
case 11:
name = "void";
rettype = debug_make_void_type (dhandle);
break;
case 12:
name = "float";
rettype = debug_make_float_type (dhandle, 4);
break;
case 13:
name = "double";
rettype = debug_make_float_type (dhandle, 8);
break;
case 14:
name = "long double";
rettype = debug_make_float_type (dhandle, 8);
break;
case 15:
name = "integer";
rettype = debug_make_int_type (dhandle, 4, FALSE);
break;
case 16:
name = "boolean";
rettype = debug_make_bool_type (dhandle, 4);
break;
case 17:
name = "short real";
rettype = debug_make_float_type (dhandle, 4);
break;
case 18:
name = "real";
rettype = debug_make_float_type (dhandle, 8);
break;
case 19:
name = "stringptr";
rettype = NULL;
break;
case 20:
name = "character";
rettype = debug_make_int_type (dhandle, 1, TRUE);
break;
case 21:
name = "logical*1";
rettype = debug_make_bool_type (dhandle, 1);
break;
case 22:
name = "logical*2";
rettype = debug_make_bool_type (dhandle, 2);
break;
case 23:
name = "logical*4";
rettype = debug_make_bool_type (dhandle, 4);
break;
case 24:
name = "logical";
rettype = debug_make_bool_type (dhandle, 4);
break;
case 25:
name = "complex";
rettype = debug_make_complex_type (dhandle, 8);
break;
case 26:
name = "double complex";
rettype = debug_make_complex_type (dhandle, 16);
break;
case 27:
name = "integer*1";
rettype = debug_make_int_type (dhandle, 1, FALSE);
break;
case 28:
name = "integer*2";
rettype = debug_make_int_type (dhandle, 2, FALSE);
break;
case 29:
name = "integer*4";
rettype = debug_make_int_type (dhandle, 4, FALSE);
break;
case 30:
name = "wchar";
rettype = debug_make_int_type (dhandle, 2, FALSE);
break;
case 31:
name = "long long";
rettype = debug_make_int_type (dhandle, 8, FALSE);
break;
case 32:
name = "unsigned long long";
rettype = debug_make_int_type (dhandle, 8, TRUE);
break;
case 33:
name = "logical*8";
rettype = debug_make_bool_type (dhandle, 8);
break;
case 34:
name = "integer*8";
rettype = debug_make_int_type (dhandle, 8, FALSE);
break;
default:
abort ();
}
rettype = debug_name_type (dhandle, name, rettype);
info->xcoff_types[-typenum] = rettype;
return rettype;
}
static debug_type
stab_find_tagged_type (void *dhandle, struct stab_handle *info,
const char *p, int len, enum debug_type_kind kind)
{
char *name;
debug_type dtype;
struct stab_tag *st;
name = savestring (p, len);
dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL);
if (dtype != DEBUG_TYPE_NULL)
{
free (name);
return dtype;
}
for (st = info->tags; st != NULL; st = st->next)
{
if (st->name[0] == name[0]
&& strcmp (st->name, name) == 0)
{
if (st->kind == DEBUG_KIND_ILLEGAL)
st->kind = kind;
free (name);
break;
}
}
if (st == NULL)
{
st = (struct stab_tag *) xmalloc (sizeof *st);
memset (st, 0, sizeof *st);
st->next = info->tags;
st->name = name;
st->kind = kind;
st->slot = DEBUG_TYPE_NULL;
st->type = debug_make_indirect_type (dhandle, &st->slot, name);
info->tags = st;
}
return st->type;
}
struct stab_demangle_typestring
{
const char *typestring;
unsigned int len;
};
struct stab_demangle_info
{
void *dhandle;
struct stab_handle *info;
debug_type *args;
bfd_boolean varargs;
struct stab_demangle_typestring *typestrings;
unsigned int typestring_count;
unsigned int typestring_alloc;
};
static void stab_bad_demangle (const char *);
static unsigned int stab_demangle_count (const char **);
static bfd_boolean stab_demangle_get_count (const char **, unsigned int *);
static bfd_boolean stab_demangle_prefix
(struct stab_demangle_info *, const char **, unsigned int);
static bfd_boolean stab_demangle_function_name
(struct stab_demangle_info *, const char **, const char *);
static bfd_boolean stab_demangle_signature
(struct stab_demangle_info *, const char **);
static bfd_boolean stab_demangle_qualified
(struct stab_demangle_info *, const char **, debug_type *);
static bfd_boolean stab_demangle_template
(struct stab_demangle_info *, const char **, char **);
static bfd_boolean stab_demangle_class
(struct stab_demangle_info *, const char **, const char **);
static bfd_boolean stab_demangle_args
(struct stab_demangle_info *, const char **, debug_type **, bfd_boolean *);
static bfd_boolean stab_demangle_arg
(struct stab_demangle_info *, const char **, debug_type **,
unsigned int *, unsigned int *);
static bfd_boolean stab_demangle_type
(struct stab_demangle_info *, const char **, debug_type *);
static bfd_boolean stab_demangle_fund_type
(struct stab_demangle_info *, const char **, debug_type *);
static bfd_boolean stab_demangle_remember_type
(struct stab_demangle_info *, const char *, int);
static void
stab_bad_demangle (const char *s)
{
fprintf (stderr, _("bad mangled name `%s'\n"), s);
}
static unsigned int
stab_demangle_count (const char **pp)
{
unsigned int count;
count = 0;
while (ISDIGIT (**pp))
{
count *= 10;
count += **pp - '0';
++*pp;
}
return count;
}
static bfd_boolean
stab_demangle_get_count (const char **pp, unsigned int *pi)
{
if (! ISDIGIT (**pp))
return FALSE;
*pi = **pp - '0';
++*pp;
if (ISDIGIT (**pp))
{
unsigned int count;
const char *p;
count = *pi;
p = *pp;
do
{
count *= 10;
count += *p - '0';
++p;
}
while (ISDIGIT (*p));
if (*p == '_')
{
*pp = p + 1;
*pi = count;
}
}
return TRUE;
}
static debug_type *
stab_demangle_argtypes (void *dhandle, struct stab_handle *info,
const char *physname, bfd_boolean *pvarargs,
unsigned int physname_len)
{
struct stab_demangle_info minfo;
if (physname[0] == '_' && physname[1] == 'Z')
return stab_demangle_v3_argtypes (dhandle, info, physname, pvarargs);
minfo.dhandle = dhandle;
minfo.info = info;
minfo.args = NULL;
minfo.varargs = FALSE;
minfo.typestring_alloc = 10;
minfo.typestrings = ((struct stab_demangle_typestring *)
xmalloc (minfo.typestring_alloc
* sizeof *minfo.typestrings));
minfo.typestring_count = 0;
if (! stab_demangle_prefix (&minfo, &physname, physname_len))
goto error_return;
if (*physname != '\0')
{
if (! stab_demangle_signature (&minfo, &physname))
goto error_return;
}
free (minfo.typestrings);
minfo.typestrings = NULL;
if (minfo.args == NULL)
fprintf (stderr, _("no argument types in mangled string\n"));
*pvarargs = minfo.varargs;
return minfo.args;
error_return:
if (minfo.typestrings != NULL)
free (minfo.typestrings);
return NULL;
}
static bfd_boolean
stab_demangle_prefix (struct stab_demangle_info *minfo, const char **pp,
unsigned int physname_len)
{
const char *scan;
unsigned int i;
if (physname_len)
scan = *pp + physname_len;
else
{
scan = *pp;
do
scan = strchr (scan, '_');
while (scan != NULL && *++scan != '_');
if (scan == NULL)
{
stab_bad_demangle (*pp);
return FALSE;
}
--scan;
i = strspn (scan, "_");
if (i > 2)
scan += i - 2;
}
if (scan == *pp
&& (ISDIGIT (scan[2])
|| scan[2] == 'Q'
|| scan[2] == 't'))
{
*pp = scan + 2;
return TRUE;
}
else if (scan == *pp
&& ! ISDIGIT (scan[2])
&& scan[2] != 't')
{
while (*scan == '_')
++scan;
scan = strstr (scan, "__");
if (scan == NULL || scan[2] == '\0')
{
stab_bad_demangle (*pp);
return FALSE;
}
return stab_demangle_function_name (minfo, pp, scan);
}
else if (scan[2] != '\0')
{
return stab_demangle_function_name (minfo, pp, scan);
}
else
{
stab_bad_demangle (*pp);
return FALSE;
}
}
static bfd_boolean
stab_demangle_function_name (struct stab_demangle_info *minfo,
const char **pp, const char *scan)
{
const char *name;
name = *pp;
*pp = scan + 2;
if (*pp - name >= 5
&& strncmp (name, "type", 4) == 0
&& (name[4] == '$' || name[4] == '.'))
{
const char *tem;
tem = name + 5;
if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
return FALSE;
}
else if (name[0] == '_'
&& name[1] == '_'
&& name[2] == 'o'
&& name[3] == 'p')
{
const char *tem;
tem = name + 4;
if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
return FALSE;
}
return TRUE;
}
static bfd_boolean
stab_demangle_signature (struct stab_demangle_info *minfo, const char **pp)
{
const char *orig;
bfd_boolean expect_func, func_done;
const char *hold;
orig = *pp;
expect_func = FALSE;
func_done = FALSE;
hold = NULL;
while (**pp != '\0')
{
switch (**pp)
{
case 'Q':
hold = *pp;
if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL)
|| ! stab_demangle_remember_type (minfo, hold, *pp - hold))
return FALSE;
expect_func = TRUE;
hold = NULL;
break;
case 'S':
if (hold == NULL)
hold = *pp;
++*pp;
break;
case 'C':
if (hold == NULL)
hold = *pp;
++*pp;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (hold == NULL)
hold = *pp;
if (! stab_demangle_class (minfo, pp, (const char **) NULL)
|| ! stab_demangle_remember_type (minfo, hold, *pp - hold))
return FALSE;
expect_func = TRUE;
hold = NULL;
break;
case 'F':
hold = NULL;
func_done = TRUE;
++*pp;
if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
return FALSE;
break;
case 't':
if (hold == NULL)
hold = *pp;
if (! stab_demangle_template (minfo, pp, (char **) NULL)
|| ! stab_demangle_remember_type (minfo, hold, *pp - hold))
return FALSE;
hold = NULL;
expect_func = TRUE;
break;
case '_':
stab_bad_demangle (orig);
return FALSE;
default:
func_done = TRUE;
if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
return FALSE;
break;
}
if (expect_func)
{
func_done = TRUE;
if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
return FALSE;
}
}
if (! func_done)
{
if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
return FALSE;
}
return TRUE;
}
static bfd_boolean
stab_demangle_qualified (struct stab_demangle_info *minfo, const char **pp,
debug_type *ptype)
{
const char *orig;
const char *p;
unsigned int qualifiers;
debug_type context;
orig = *pp;
switch ((*pp)[1])
{
case '_':
p = *pp + 2;
if (! ISDIGIT (*p) || *p == '0')
{
stab_bad_demangle (orig);
return FALSE;
}
qualifiers = atoi (p);
while (ISDIGIT (*p))
++p;
if (*p != '_')
{
stab_bad_demangle (orig);
return FALSE;
}
*pp = p + 1;
break;
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
qualifiers = (*pp)[1] - '0';
if ((*pp)[2] == '_')
++*pp;
*pp += 2;
break;
case '0':
default:
stab_bad_demangle (orig);
return FALSE;
}
context = DEBUG_TYPE_NULL;
while (qualifiers-- > 0)
{
if (**pp == '_')
++*pp;
if (**pp == 't')
{
char *name;
if (! stab_demangle_template (minfo, pp,
ptype != NULL ? &name : NULL))
return FALSE;
if (ptype != NULL)
{
context = stab_find_tagged_type (minfo->dhandle, minfo->info,
name, strlen (name),
DEBUG_KIND_CLASS);
free (name);
if (context == DEBUG_TYPE_NULL)
return FALSE;
}
}
else
{
unsigned int len;
len = stab_demangle_count (pp);
if (strlen (*pp) < len)
{
stab_bad_demangle (orig);
return FALSE;
}
if (ptype != NULL)
{
const debug_field *fields;
fields = NULL;
if (context != DEBUG_TYPE_NULL)
fields = debug_get_fields (minfo->dhandle, context);
context = DEBUG_TYPE_NULL;
if (fields != NULL)
{
char *name;
name = savestring (*pp, len);
for (; *fields != DEBUG_FIELD_NULL; fields++)
{
debug_type ft;
const char *dn;
ft = debug_get_field_type (minfo->dhandle, *fields);
if (ft == NULL)
return FALSE;
dn = debug_get_type_name (minfo->dhandle, ft);
if (dn != NULL && strcmp (dn, name) == 0)
{
context = ft;
break;
}
}
free (name);
}
if (context == DEBUG_TYPE_NULL)
{
if (qualifiers == 0)
{
char *name;
name = savestring (*pp, len);
context = debug_find_named_type (minfo->dhandle,
name);
free (name);
}
if (context == DEBUG_TYPE_NULL)
{
context = stab_find_tagged_type (minfo->dhandle,
minfo->info,
*pp, len,
(qualifiers == 0
? DEBUG_KIND_ILLEGAL
: DEBUG_KIND_CLASS));
if (context == DEBUG_TYPE_NULL)
return FALSE;
}
}
}
*pp += len;
}
}
if (ptype != NULL)
*ptype = context;
return TRUE;
}
static bfd_boolean
stab_demangle_template (struct stab_demangle_info *minfo, const char **pp,
char **pname)
{
const char *orig;
unsigned int r, i;
orig = *pp;
++*pp;
r = stab_demangle_count (pp);
if (r == 0 || strlen (*pp) < r)
{
stab_bad_demangle (orig);
return FALSE;
}
*pp += r;
if (stab_demangle_get_count (pp, &r) == 0)
{
stab_bad_demangle (orig);
return FALSE;
}
for (i = 0; i < r; i++)
{
if (**pp == 'Z')
{
++*pp;
if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
return FALSE;
}
else
{
const char *old_p;
bfd_boolean pointerp, realp, integralp, charp, boolp;
bfd_boolean done;
old_p = *pp;
pointerp = FALSE;
realp = FALSE;
integralp = FALSE;
charp = FALSE;
boolp = FALSE;
done = FALSE;
if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
return FALSE;
while (*old_p != '\0' && ! done)
{
switch (*old_p)
{
case 'P':
case 'p':
case 'R':
pointerp = TRUE;
done = TRUE;
break;
case 'C':
case 'S':
case 'U':
case 'V':
case 'F':
case 'M':
case 'O':
++old_p;
break;
case 'Q':
integralp = TRUE;
done = TRUE;
break;
case 'T':
abort ();
case 'v':
abort ();
case 'x':
case 'l':
case 'i':
case 's':
case 'w':
integralp = TRUE;
done = TRUE;
break;
case 'b':
boolp = TRUE;
done = TRUE;
break;
case 'c':
charp = TRUE;
done = TRUE;
break;
case 'r':
case 'd':
case 'f':
realp = TRUE;
done = TRUE;
break;
default:
integralp = TRUE;
done = TRUE;
break;
}
}
if (integralp)
{
if (**pp == 'm')
++*pp;
while (ISDIGIT (**pp))
++*pp;
}
else if (charp)
{
unsigned int val;
if (**pp == 'm')
++*pp;
val = stab_demangle_count (pp);
if (val == 0)
{
stab_bad_demangle (orig);
return FALSE;
}
}
else if (boolp)
{
unsigned int val;
val = stab_demangle_count (pp);
if (val != 0 && val != 1)
{
stab_bad_demangle (orig);
return FALSE;
}
}
else if (realp)
{
if (**pp == 'm')
++*pp;
while (ISDIGIT (**pp))
++*pp;
if (**pp == '.')
{
++*pp;
while (ISDIGIT (**pp))
++*pp;
}
if (**pp == 'e')
{
++*pp;
while (ISDIGIT (**pp))
++*pp;
}
}
else if (pointerp)
{
unsigned int len;
len = stab_demangle_count (pp);
if (len == 0)
{
stab_bad_demangle (orig);
return FALSE;
}
*pp += len;
}
}
}
if (pname != NULL)
{
char *s1, *s2, *s3, *s4 = NULL;
char *from, *to;
s1 = savestring (orig, *pp - orig);
s2 = concat ("NoSuchStrinG__", s1, (const char *) NULL);
free (s1);
s3 = cplus_demangle (s2, DMGL_ANSI);
free (s2);
if (s3 != NULL)
s4 = strstr (s3, "::NoSuchStrinG");
if (s3 == NULL || s4 == NULL)
{
stab_bad_demangle (orig);
if (s3 != NULL)
free (s3);
return FALSE;
}
for (from = to = s3; from != s4; ++from)
if (*from != ' '
|| (from[1] == '>' && from > s3 && from[-1] == '>'))
*to++ = *from;
*pname = savestring (s3, to - s3);
free (s3);
}
return TRUE;
}
static bfd_boolean
stab_demangle_class (struct stab_demangle_info *minfo ATTRIBUTE_UNUSED,
const char **pp, const char **pstart)
{
const char *orig;
unsigned int n;
orig = *pp;
n = stab_demangle_count (pp);
if (strlen (*pp) < n)
{
stab_bad_demangle (orig);
return FALSE;
}
if (pstart != NULL)
*pstart = *pp;
*pp += n;
return TRUE;
}
static bfd_boolean
stab_demangle_args (struct stab_demangle_info *minfo, const char **pp,
debug_type **pargs, bfd_boolean *pvarargs)
{
const char *orig;
unsigned int alloc, count;
orig = *pp;
alloc = 10;
if (pargs != NULL)
{
*pargs = (debug_type *) xmalloc (alloc * sizeof **pargs);
*pvarargs = FALSE;
}
count = 0;
while (**pp != '_' && **pp != '\0' && **pp != 'e')
{
if (**pp == 'N' || **pp == 'T')
{
char temptype;
unsigned int r, t;
temptype = **pp;
++*pp;
if (temptype == 'T')
r = 1;
else
{
if (! stab_demangle_get_count (pp, &r))
{
stab_bad_demangle (orig);
return FALSE;
}
}
if (! stab_demangle_get_count (pp, &t))
{
stab_bad_demangle (orig);
return FALSE;
}
if (t >= minfo->typestring_count)
{
stab_bad_demangle (orig);
return FALSE;
}
while (r-- > 0)
{
const char *tem;
tem = minfo->typestrings[t].typestring;
if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc))
return FALSE;
}
}
else
{
if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc))
return FALSE;
}
}
if (pargs != NULL)
(*pargs)[count] = DEBUG_TYPE_NULL;
if (**pp == 'e')
{
if (pargs != NULL)
*pvarargs = TRUE;
++*pp;
}
return TRUE;
}
static bfd_boolean
stab_demangle_arg (struct stab_demangle_info *minfo, const char **pp,
debug_type **pargs, unsigned int *pcount,
unsigned int *palloc)
{
const char *start;
debug_type type;
start = *pp;
if (! stab_demangle_type (minfo, pp,
pargs == NULL ? (debug_type *) NULL : &type)
|| ! stab_demangle_remember_type (minfo, start, *pp - start))
return FALSE;
if (pargs != NULL)
{
if (type == DEBUG_TYPE_NULL)
return FALSE;
if (*pcount + 1 >= *palloc)
{
*palloc += 10;
*pargs = ((debug_type *)
xrealloc (*pargs, *palloc * sizeof **pargs));
}
(*pargs)[*pcount] = type;
++*pcount;
}
return TRUE;
}
static bfd_boolean
stab_demangle_type (struct stab_demangle_info *minfo, const char **pp,
debug_type *ptype)
{
const char *orig;
orig = *pp;
switch (**pp)
{
case 'P':
case 'p':
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
*ptype = debug_make_pointer_type (minfo->dhandle, *ptype);
break;
case 'R':
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
*ptype = debug_make_reference_type (minfo->dhandle, *ptype);
break;
case 'A':
{
unsigned long high;
++*pp;
high = 0;
while (**pp != '\0' && **pp != '_')
{
if (! ISDIGIT (**pp))
{
stab_bad_demangle (orig);
return FALSE;
}
high *= 10;
high += **pp - '0';
++*pp;
}
if (**pp != '_')
{
stab_bad_demangle (orig);
return FALSE;
}
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
{
debug_type int_type;
int_type = debug_find_named_type (minfo->dhandle, "int");
if (int_type == NULL)
int_type = debug_make_int_type (minfo->dhandle, 4, FALSE);
*ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type,
0, high, FALSE);
}
}
break;
case 'T':
{
unsigned int i;
const char *p;
++*pp;
if (! stab_demangle_get_count (pp, &i))
{
stab_bad_demangle (orig);
return FALSE;
}
if (i >= minfo->typestring_count)
{
stab_bad_demangle (orig);
return FALSE;
}
p = minfo->typestrings[i].typestring;
if (! stab_demangle_type (minfo, &p, ptype))
return FALSE;
}
break;
case 'F':
{
debug_type *args;
bfd_boolean varargs;
++*pp;
if (! stab_demangle_args (minfo, pp,
(ptype == NULL
? (debug_type **) NULL
: &args),
(ptype == NULL
? (bfd_boolean *) NULL
: &varargs)))
return FALSE;
if (**pp != '_')
{
stab_bad_demangle (orig);
return FALSE;
}
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
*ptype = debug_make_function_type (minfo->dhandle, *ptype, args,
varargs);
}
break;
case 'M':
case 'O':
{
bfd_boolean memberp, constp, volatilep;
debug_type class_type = DEBUG_TYPE_NULL;
debug_type *args;
bfd_boolean varargs;
unsigned int n;
const char *name;
memberp = **pp == 'M';
constp = FALSE;
volatilep = FALSE;
args = NULL;
varargs = FALSE;
++*pp;
if (ISDIGIT (**pp))
{
n = stab_demangle_count (pp);
if (strlen (*pp) < n)
{
stab_bad_demangle (orig);
return FALSE;
}
name = *pp;
*pp += n;
if (ptype != NULL)
{
class_type = stab_find_tagged_type (minfo->dhandle,
minfo->info,
name, (int) n,
DEBUG_KIND_CLASS);
if (class_type == DEBUG_TYPE_NULL)
return FALSE;
}
}
else if (**pp == 'Q')
{
if (! stab_demangle_qualified (minfo, pp,
(ptype == NULL
? (debug_type *) NULL
: &class_type)))
return FALSE;
}
else
{
stab_bad_demangle (orig);
return FALSE;
}
if (memberp)
{
if (**pp == 'C')
{
constp = TRUE;
++*pp;
}
else if (**pp == 'V')
{
volatilep = TRUE;
++*pp;
}
if (**pp != 'F')
{
stab_bad_demangle (orig);
return FALSE;
}
++*pp;
if (! stab_demangle_args (minfo, pp,
(ptype == NULL
? (debug_type **) NULL
: &args),
(ptype == NULL
? (bfd_boolean *) NULL
: &varargs)))
return FALSE;
}
if (**pp != '_')
{
stab_bad_demangle (orig);
return FALSE;
}
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
{
if (! memberp)
*ptype = debug_make_offset_type (minfo->dhandle, class_type,
*ptype);
else
{
*ptype = debug_make_method_type (minfo->dhandle, *ptype,
class_type, args, varargs);
}
}
}
break;
case 'G':
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
break;
case 'C':
++*pp;
if (! stab_demangle_type (minfo, pp, ptype))
return FALSE;
if (ptype != NULL)
*ptype = debug_make_const_type (minfo->dhandle, *ptype);
break;
case 'Q':
{
const char *hold;
hold = *pp;
if (! stab_demangle_qualified (minfo, pp, ptype))
return FALSE;
}
break;
default:
if (! stab_demangle_fund_type (minfo, pp, ptype))
return FALSE;
break;
}
return TRUE;
}
static bfd_boolean
stab_demangle_fund_type (struct stab_demangle_info *minfo, const char **pp,
debug_type *ptype)
{
const char *orig;
bfd_boolean constp, volatilep, unsignedp, signedp;
bfd_boolean done;
orig = *pp;
constp = FALSE;
volatilep = FALSE;
unsignedp = FALSE;
signedp = FALSE;
done = FALSE;
while (! done)
{
switch (**pp)
{
case 'C':
constp = TRUE;
++*pp;
break;
case 'U':
unsignedp = TRUE;
++*pp;
break;
case 'S':
signedp = TRUE;
++*pp;
break;
case 'V':
volatilep = TRUE;
++*pp;
break;
default:
done = TRUE;
break;
}
}
switch (**pp)
{
case '\0':
case '_':
stab_bad_demangle (orig);
break;
case 'v':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "void");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_void_type (minfo->dhandle);
}
++*pp;
break;
case 'x':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle,
(unsignedp
? "long long unsigned int"
: "long long int"));
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp);
}
++*pp;
break;
case 'l':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle,
(unsignedp
? "long unsigned int"
: "long int"));
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
}
++*pp;
break;
case 'i':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle,
(unsignedp
? "unsigned int"
: "int"));
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
}
++*pp;
break;
case 's':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle,
(unsignedp
? "short unsigned int"
: "short int"));
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp);
}
++*pp;
break;
case 'b':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "bool");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_bool_type (minfo->dhandle, 4);
}
++*pp;
break;
case 'c':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle,
(unsignedp
? "unsigned char"
: (signedp
? "signed char"
: "char")));
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp);
}
++*pp;
break;
case 'w':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "__wchar_t");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_int_type (minfo->dhandle, 2, TRUE);
}
++*pp;
break;
case 'r':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "long double");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_float_type (minfo->dhandle, 8);
}
++*pp;
break;
case 'd':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "double");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_float_type (minfo->dhandle, 8);
}
++*pp;
break;
case 'f':
if (ptype != NULL)
{
*ptype = debug_find_named_type (minfo->dhandle, "float");
if (*ptype == DEBUG_TYPE_NULL)
*ptype = debug_make_float_type (minfo->dhandle, 4);
}
++*pp;
break;
case 'G':
++*pp;
if (! ISDIGIT (**pp))
{
stab_bad_demangle (orig);
return FALSE;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
const char *hold;
if (! stab_demangle_class (minfo, pp, &hold))
return FALSE;
if (ptype != NULL)
{
char *name;
name = savestring (hold, *pp - hold);
*ptype = debug_find_named_type (minfo->dhandle, name);
free (name);
if (*ptype == DEBUG_TYPE_NULL)
{
*ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
hold, *pp - hold,
DEBUG_KIND_ILLEGAL);
if (*ptype == DEBUG_TYPE_NULL)
return FALSE;
}
}
}
break;
case 't':
{
char *name;
if (! stab_demangle_template (minfo, pp,
ptype != NULL ? &name : NULL))
return FALSE;
if (ptype != NULL)
{
*ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
name, strlen (name),
DEBUG_KIND_CLASS);
free (name);
if (*ptype == DEBUG_TYPE_NULL)
return FALSE;
}
}
break;
default:
stab_bad_demangle (orig);
return FALSE;
}
if (ptype != NULL)
{
if (constp)
*ptype = debug_make_const_type (minfo->dhandle, *ptype);
if (volatilep)
*ptype = debug_make_volatile_type (minfo->dhandle, *ptype);
}
return TRUE;
}
static bfd_boolean
stab_demangle_remember_type (struct stab_demangle_info *minfo,
const char *p, int len)
{
if (minfo->typestring_count >= minfo->typestring_alloc)
{
minfo->typestring_alloc += 10;
minfo->typestrings = ((struct stab_demangle_typestring *)
xrealloc (minfo->typestrings,
(minfo->typestring_alloc
* sizeof *minfo->typestrings)));
}
minfo->typestrings[minfo->typestring_count].typestring = p;
minfo->typestrings[minfo->typestring_count].len = (unsigned int) len;
++minfo->typestring_count;
return TRUE;
}
static debug_type *
stab_demangle_v3_argtypes (void *dhandle, struct stab_handle *info,
const char *physname, bfd_boolean *pvarargs)
{
struct demangle_component *dc;
void *mem;
debug_type *pargs;
dc = cplus_demangle_v3_components (physname, DMGL_PARAMS | DMGL_ANSI, &mem);
if (dc == NULL)
{
stab_bad_demangle (physname);
return NULL;
}
if (dc->type != DEMANGLE_COMPONENT_TYPED_NAME
|| dc->u.s_binary.right->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
{
fprintf (stderr, _("Demangled name is not a function\n"));
free (mem);
return NULL;
}
pargs = stab_demangle_v3_arglist (dhandle, info,
dc->u.s_binary.right->u.s_binary.right,
pvarargs);
free (mem);
return pargs;
}
static debug_type *
stab_demangle_v3_arglist (void *dhandle, struct stab_handle *info,
struct demangle_component *arglist,
bfd_boolean *pvarargs)
{
struct demangle_component *dc;
unsigned int alloc, count;
debug_type *pargs;
alloc = 10;
pargs = (debug_type *) xmalloc (alloc * sizeof *pargs);
*pvarargs = FALSE;
count = 0;
for (dc = arglist;
dc != NULL;
dc = dc->u.s_binary.right)
{
debug_type arg;
bfd_boolean varargs;
if (dc->type != DEMANGLE_COMPONENT_ARGLIST)
{
fprintf (stderr, _("Unexpected type in v3 arglist demangling\n"));
free (pargs);
return NULL;
}
arg = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left,
NULL, &varargs);
if (arg == NULL)
{
if (varargs)
{
*pvarargs = TRUE;
continue;
}
free (pargs);
return NULL;
}
if (count + 1 >= alloc)
{
alloc += 10;
pargs = (debug_type *) xrealloc (pargs, alloc * sizeof *pargs);
}
pargs[count] = arg;
++count;
}
pargs[count] = DEBUG_TYPE_NULL;
return pargs;
}
static debug_type
stab_demangle_v3_arg (void *dhandle, struct stab_handle *info,
struct demangle_component *dc, debug_type context,
bfd_boolean *pvarargs)
{
debug_type dt;
if (pvarargs != NULL)
*pvarargs = FALSE;
switch (dc->type)
{
case DEMANGLE_COMPONENT_LOCAL_NAME:
case DEMANGLE_COMPONENT_TYPED_NAME:
case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
case DEMANGLE_COMPONENT_CTOR:
case DEMANGLE_COMPONENT_DTOR:
case DEMANGLE_COMPONENT_JAVA_CLASS:
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
case DEMANGLE_COMPONENT_COMPLEX:
case DEMANGLE_COMPONENT_IMAGINARY:
case DEMANGLE_COMPONENT_VENDOR_TYPE:
case DEMANGLE_COMPONENT_ARRAY_TYPE:
case DEMANGLE_COMPONENT_PTRMEM_TYPE:
case DEMANGLE_COMPONENT_ARGLIST:
default:
fprintf (stderr, _("Unrecognized demangle component %d\n"),
(int) dc->type);
return NULL;
case DEMANGLE_COMPONENT_NAME:
if (context != NULL)
{
const debug_field *fields;
fields = debug_get_fields (dhandle, context);
if (fields != NULL)
{
for (; *fields != DEBUG_FIELD_NULL; fields++)
{
debug_type ft;
const char *dn;
ft = debug_get_field_type (dhandle, *fields);
if (ft == NULL)
return NULL;
dn = debug_get_type_name (dhandle, ft);
if (dn != NULL
&& (int) strlen (dn) == dc->u.s_name.len
&& strncmp (dn, dc->u.s_name.s, dc->u.s_name.len) == 0)
return ft;
}
}
}
return stab_find_tagged_type (dhandle, info, dc->u.s_name.s,
dc->u.s_name.len, DEBUG_KIND_ILLEGAL);
case DEMANGLE_COMPONENT_QUAL_NAME:
context = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left,
context, NULL);
if (context == NULL)
return NULL;
return stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.right,
context, NULL);
case DEMANGLE_COMPONENT_TEMPLATE:
{
char *p;
size_t alc;
p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
if (p == NULL)
{
fprintf (stderr, _("Failed to print demangled template\n"));
return NULL;
}
dt = stab_find_tagged_type (dhandle, info, p, strlen (p),
DEBUG_KIND_CLASS);
free (p);
return dt;
}
case DEMANGLE_COMPONENT_SUB_STD:
return stab_find_tagged_type (dhandle, info, dc->u.s_string.string,
dc->u.s_string.len, DEBUG_KIND_ILLEGAL);
case DEMANGLE_COMPONENT_RESTRICT:
case DEMANGLE_COMPONENT_VOLATILE:
case DEMANGLE_COMPONENT_CONST:
case DEMANGLE_COMPONENT_POINTER:
case DEMANGLE_COMPONENT_REFERENCE:
dt = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, NULL,
NULL);
if (dt == NULL)
return NULL;
switch (dc->type)
{
default:
abort ();
case DEMANGLE_COMPONENT_RESTRICT:
return dt;
case DEMANGLE_COMPONENT_VOLATILE:
return debug_make_volatile_type (dhandle, dt);
case DEMANGLE_COMPONENT_CONST:
return debug_make_const_type (dhandle, dt);
case DEMANGLE_COMPONENT_POINTER:
return debug_make_pointer_type (dhandle, dt);
case DEMANGLE_COMPONENT_REFERENCE:
return debug_make_reference_type (dhandle, dt);
}
case DEMANGLE_COMPONENT_FUNCTION_TYPE:
{
debug_type *pargs;
bfd_boolean varargs;
if (dc->u.s_binary.left == NULL)
{
dt = debug_make_void_type (dhandle);
}
else
dt = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, NULL,
NULL);
if (dt == NULL)
return NULL;
pargs = stab_demangle_v3_arglist (dhandle, info,
dc->u.s_binary.right,
&varargs);
if (pargs == NULL)
return NULL;
return debug_make_function_type (dhandle, dt, pargs, varargs);
}
case DEMANGLE_COMPONENT_BUILTIN_TYPE:
{
char *p;
size_t alc;
debug_type ret;
p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
if (p == NULL)
{
fprintf (stderr, _("Couldn't get demangled builtin type\n"));
return NULL;
}
if (strcmp (p, "signed char") == 0)
ret = debug_make_int_type (dhandle, 1, FALSE);
else if (strcmp (p, "bool") == 0)
ret = debug_make_bool_type (dhandle, 1);
else if (strcmp (p, "char") == 0)
ret = debug_make_int_type (dhandle, 1, FALSE);
else if (strcmp (p, "double") == 0)
ret = debug_make_float_type (dhandle, 8);
else if (strcmp (p, "long double") == 0)
ret = debug_make_float_type (dhandle, 8);
else if (strcmp (p, "float") == 0)
ret = debug_make_float_type (dhandle, 4);
else if (strcmp (p, "__float128") == 0)
ret = debug_make_float_type (dhandle, 16);
else if (strcmp (p, "unsigned char") == 0)
ret = debug_make_int_type (dhandle, 1, TRUE);
else if (strcmp (p, "int") == 0)
ret = debug_make_int_type (dhandle, 4, FALSE);
else if (strcmp (p, "unsigned int") == 0)
ret = debug_make_int_type (dhandle, 4, TRUE);
else if (strcmp (p, "long") == 0)
ret = debug_make_int_type (dhandle, 4, FALSE);
else if (strcmp (p, "unsigned long") == 0)
ret = debug_make_int_type (dhandle, 4, TRUE);
else if (strcmp (p, "__int128") == 0)
ret = debug_make_int_type (dhandle, 16, FALSE);
else if (strcmp (p, "unsigned __int128") == 0)
ret = debug_make_int_type (dhandle, 16, TRUE);
else if (strcmp (p, "short") == 0)
ret = debug_make_int_type (dhandle, 2, FALSE);
else if (strcmp (p, "unsigned short") == 0)
ret = debug_make_int_type (dhandle, 2, TRUE);
else if (strcmp (p, "void") == 0)
ret = debug_make_void_type (dhandle);
else if (strcmp (p, "wchar_t") == 0)
ret = debug_make_int_type (dhandle, 4, TRUE);
else if (strcmp (p, "long long") == 0)
ret = debug_make_int_type (dhandle, 8, FALSE);
else if (strcmp (p, "unsigned long long") == 0)
ret = debug_make_int_type (dhandle, 8, TRUE);
else if (strcmp (p, "...") == 0)
{
if (pvarargs == NULL)
fprintf (stderr, _("Unexpected demangled varargs\n"));
else
*pvarargs = TRUE;
ret = NULL;
}
else
{
fprintf (stderr, _("Unrecognized demangled builtin type\n"));
ret = NULL;
}
free (p);
return ret;
}
}
}