/* stabs.c -- Parse stabs debugging information
- Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1995-2020 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
};
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 *);
+ (void *, struct stab_handle *, int, int, bfd_vma,
+ const char *, 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 *);
+ (void *, struct stab_handle *, const char *, const char **,
+ debug_type **, const char *);
+static bfd_boolean parse_stab_type_number
+ (const char **, int *, const char *);
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 **);
+ (void *, struct stab_handle *, const char *, const char **,
+ const int *, const char *);
+static debug_type parse_stab_sun_builtin_type
+ (void *, const char **, const char *);
+static debug_type parse_stab_sun_floating_type
+ (void *, const char **, const char *);
+static debug_type parse_stab_enum_type
+ (void *, const char **, const char *);
static debug_type parse_stab_struct_type
(void *, struct stab_handle *, const char *, const char **,
- bfd_boolean, const int *);
+ bfd_boolean, const int *, const char *);
static bfd_boolean parse_stab_baseclasses
- (void *, struct stab_handle *, const char **, debug_baseclass **);
+ (void *, struct stab_handle *, const char **, debug_baseclass **,
+ const char *);
static bfd_boolean parse_stab_struct_fields
- (void *, struct stab_handle *, const char **, debug_field **, bfd_boolean *);
+ (void *, struct stab_handle *, const char **, debug_field **,
+ bfd_boolean *, const char *);
static bfd_boolean parse_stab_cpp_abbrev
- (void *, struct stab_handle *, const char **, debug_field *);
+ (void *, struct stab_handle *, const char **, debug_field *, const char *);
static bfd_boolean parse_stab_one_struct_field
(void *, struct stab_handle *, const char **, const char *,
- debug_field *, bfd_boolean *);
+ debug_field *, bfd_boolean *, const char *);
static bfd_boolean parse_stab_members
(void *, struct stab_handle *, const char *, const char **, const int *,
- debug_method **);
+ debug_method **, const char *);
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 *);
+ bfd_boolean *, const char *);
static debug_type parse_stab_array_type
- (void *, struct stab_handle *, const char **, bfd_boolean);
+ (void *, struct stab_handle *, const char **, bfd_boolean, const char *);
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);
(void *, struct stab_handle *, struct demangle_component *, debug_type,
bfd_boolean *);
+static int demangle_flags = DMGL_ANSI;
+
/* Save a string in memory. */
static char *
/* Read a number from a string. */
static bfd_vma
-parse_number (const char **pp, bfd_boolean *poverflow)
+parse_number (const char **pp, bfd_boolean *poverflow, const char *p_end)
{
unsigned long ul;
const char *orig;
*poverflow = FALSE;
orig = *pp;
+ if (orig >= p_end)
+ return (bfd_vma) 0;
+
+ /* Stop early if we are passed an empty string. */
+ if (*orig == 0)
+ return (bfd_vma) 0;
errno = 0;
ul = strtoul (*pp, (char **) pp, 0);
parse_stab (void *dhandle, void *handle, int type, int desc, bfd_vma value,
const char *string)
{
+ const char * string_end;
struct stab_handle *info = (struct stab_handle *) handle;
/* gcc will emit two N_SO strings per compilation unit, one for the
info->file_types = ((struct stab_types **)
xmalloc (sizeof *info->file_types));
info->file_types[0] = NULL;
-
info->so_string = NULL;
/* Now process whatever type we just got. */
}
+ string_end = string + strlen (string);
+
switch (type)
{
case N_FN:
info->within_function = TRUE;
}
- if (! parse_stab_string (dhandle, info, type, desc, value, string))
+ if (! parse_stab_string (dhandle, info, type, desc, value, string, string_end))
return FALSE;
}
break;
static bfd_boolean
parse_stab_string (void *dhandle, struct stab_handle *info, int stabtype,
- int desc, bfd_vma value, const char *string)
+ int desc ATTRIBUTE_UNUSED, bfd_vma value,
+ const char *string, const char * string_end)
{
const char *p;
char *name;
debug_type dtype;
bfd_boolean synonym;
bfd_boolean self_crossref;
- unsigned int lineno;
debug_type *slot;
p = strchr (string, ':');
}
}
- /* GCC 2.x puts the line number in desc. SunOS apparently puts in
- the number of bytes occupied by a type or object, which we
- ignore. */
- if (info->gcc_compiled >= 2)
- lineno = desc;
- else
- lineno = 0;
-
/* FIXME: Sometimes the special C++ names start with '.'. */
name = NULL;
if (string[0] == '$')
++p;
if (ISDIGIT (*p) || *p == '(' || *p == '-')
type = 'l';
+ else if (*p == 0)
+ {
+ bad_stab (string);
+ return FALSE;
+ }
else
type = *p++;
e.g. "b:c=e6,0" for "const b = blob1"
(where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */
dtype = parse_stab_type (dhandle, info, (const char *) NULL,
- &p, (debug_type **) NULL);
+ &p, (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (*p != ',')
case 'C':
/* The name of a caught exception. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL,
- &p, (debug_type **) NULL);
+ &p, (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_label (dhandle, name, dtype, value))
case 'F':
/* A function definition. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_function (dhandle, name, dtype, type == 'F', value))
{
++p;
if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL)
+ (debug_type **) NULL, string_end)
== DEBUG_TYPE_NULL)
return FALSE;
}
case 'G':
{
- char leading;
- long c;
asymbol **ps;
/* A global symbol. The value must be extracted from the
symbol table. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
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)
+ if (name != NULL)
{
- const char *n;
+ char leading;
+ long c;
- n = bfd_asymbol_name (*ps);
- if (leading != '\0' && *n == leading)
- ++n;
- if (*n == *name && strcmp (n, name) == 0)
- break;
+ 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 (c > 0)
- value = bfd_asymbol_value (*ps);
+
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
value))
return FALSE;
case 'l':
case 's':
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
/* A function parameter. */
if (*p != 'F')
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
else
{
/* pF is a two-letter code that means a function parameter in
value. Translate it into a pointer-to-function type. */
++p;
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
if (dtype != DEBUG_TYPE_NULL)
{
debug_type ftype;
{
++p;
if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL)
+ (debug_type **) NULL, string_end)
== DEBUG_TYPE_NULL)
return FALSE;
}
case 'R':
/* Parameter which is in a register. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG,
case 'r':
/* Register variable (either global or local). */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER,
case 'S':
/* Static symbol at top level of file. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC,
case 't':
/* A typedef. */
- dtype = parse_stab_type (dhandle, info, name, &p, &slot);
+ dtype = parse_stab_type (dhandle, info, name, &p, &slot, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (name == NULL)
break;
case 'T':
- /* Struct, union, or enum tag. For GNU C++, this can be be followed
+ /* Struct, union, or enum tag. For GNU C++, this can be followed
by 't' which means we are typedef'ing it as well. */
if (*p != 't')
{
++p;
}
- dtype = parse_stab_type (dhandle, info, name, &p, &slot);
+ dtype = parse_stab_type (dhandle, info, name, &p, &slot, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (name == NULL)
case 'V':
/* Static symbol of local scope */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
/* FIXME: gdb checks os9k_stabs here. */
case 'v':
/* Reference parameter. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE,
case 'a':
/* Reference parameter which is in a register. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG,
that Pascal uses it too, but when I tried it Pascal used
"x:3" (local symbol) instead. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
- (debug_type **) NULL);
+ (debug_type **) NULL, string_end);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
store the slot used if the type is being defined. */
static debug_type
-parse_stab_type (void *dhandle, struct stab_handle *info, const char *type_name, const char **pp, debug_type **slotp)
+parse_stab_type (void * dhandle,
+ struct stab_handle * info,
+ const char * type_name,
+ const char ** pp,
+ debug_type ** slotp,
+ const char * p_end)
{
const char *orig;
int typenums[2];
*slotp = NULL;
orig = *pp;
+ if (orig >= p_end)
+ return DEBUG_TYPE_NULL;
size = -1;
stringp = FALSE;
}
else
{
- if (! parse_stab_type_number (pp, typenums))
+ if (! parse_stab_type_number (pp, typenums, p_end))
return DEBUG_TYPE_NULL;
if (**pp != '=')
stringp = TRUE;
break;
+ case 0:
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+
default:
/* Ignore unrecognized type attributes, so future
compilers can invent new ones. */
case 'e':
code = DEBUG_KIND_ENUM;
break;
+ case 0:
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+
default:
/* Complain and keep going, so compilers can invent new
cross-reference types. */
hold = *pp;
/* Peek ahead at the number to detect void. */
- if (! parse_stab_type_number (pp, xtypenums))
+ if (! parse_stab_type_number (pp, xtypenums, p_end))
return DEBUG_TYPE_NULL;
if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
This means that we can deal with something like
t(1,2)=(3,4)=... which the Lucid compiler uses. */
dtype = parse_stab_type (dhandle, info, (const char *) NULL,
- pp, (debug_type **) NULL);
+ pp, (debug_type **) NULL, p_end);
if (dtype == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
parse_stab_type (dhandle, info,
(const char *) NULL,
pp,
- (debug_type **) NULL));
+ (debug_type **) NULL,
+ p_end));
break;
case '&':
dtype = (debug_make_reference_type
(dhandle,
parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL)));
+ (debug_type **) NULL, p_end)));
break;
case 'f':
dtype = (debug_make_function_type
(dhandle,
parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL),
+ (debug_type **) NULL, p_end),
(debug_type *) NULL, FALSE));
break;
parse_stab_type (dhandle, info,
(const char *) NULL,
pp,
- (debug_type **) NULL));
+ (debug_type **) NULL,
+ p_end));
break;
case 'B':
dtype = (debug_make_volatile_type
(dhandle,
parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL)));
+ (debug_type **) NULL, p_end)));
break;
case '@':
/* Member type. */
domain = parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL);
+ (debug_type **) NULL, p_end);
if (domain == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
++*pp;
memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL);
+ (debug_type **) NULL, p_end);
if (memtype == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
++*pp;
return_type = parse_stab_type (dhandle, info, (const char *) NULL,
- pp, (debug_type **) NULL);
+ pp, (debug_type **) NULL, p_end);
if (return_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (**pp != ';')
bfd_boolean varargs;
domain = parse_stab_type (dhandle, info, (const char *) NULL,
- pp, (debug_type **) NULL);
+ pp, (debug_type **) NULL, p_end);
if (domain == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
++*pp;
return_type = parse_stab_type (dhandle, info, (const char *) NULL,
- pp, (debug_type **) NULL);
+ pp, (debug_type **) NULL, p_end);
if (return_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
args[n] = parse_stab_type (dhandle, info, (const char *) NULL,
- pp, (debug_type **) NULL);
+ pp, (debug_type **) NULL, p_end);
if (args[n] == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
++n;
case 'r':
/* Range type. */
- dtype = parse_stab_range_type (dhandle, info, type_name, pp, typenums);
+ dtype = parse_stab_range_type (dhandle, info, type_name, pp, typenums, p_end);
break;
case 'b':
/* FIXME: gdb checks os9k_stabs here. */
/* Sun ACC builtin int type. */
- dtype = parse_stab_sun_builtin_type (dhandle, pp);
+ dtype = parse_stab_sun_builtin_type (dhandle, pp, p_end);
break;
case 'R':
/* Sun ACC builtin float type. */
- dtype = parse_stab_sun_floating_type (dhandle, pp);
+ dtype = parse_stab_sun_floating_type (dhandle, pp, p_end);
break;
case 'e':
/* Enumeration type. */
- dtype = parse_stab_enum_type (dhandle, pp);
+ dtype = parse_stab_enum_type (dhandle, pp, p_end);
break;
case 's':
case 'u':
/* Struct or union type. */
dtype = parse_stab_struct_type (dhandle, info, type_name, pp,
- descriptor == 's', typenums);
+ descriptor == 's', typenums, p_end);
break;
case 'a':
}
++*pp;
- dtype = parse_stab_array_type (dhandle, info, pp, stringp);
+ dtype = parse_stab_array_type (dhandle, info, pp, stringp, p_end);
break;
case 'S':
parse_stab_type (dhandle, info,
(const char *) NULL,
pp,
- (debug_type **) NULL),
+ (debug_type **) NULL,
+ p_end),
stringp);
break;
storing them in the vector TYPENUMS. */
static bfd_boolean
-parse_stab_type_number (const char **pp, int *typenums)
+parse_stab_type_number (const char **pp, int *typenums, const char *p_end)
{
const char *orig;
if (**pp != '(')
{
typenums[0] = 0;
- typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL);
+ typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL, p_end);
+ return TRUE;
}
- else
+
+ ++*pp;
+ typenums[0] = (int) parse_number (pp, (bfd_boolean *) NULL, p_end);
+ if (**pp != ',')
{
- ++*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;
+ bad_stab (orig);
+ return FALSE;
}
+ ++*pp;
+ typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL, p_end);
+ if (**pp != ')')
+ {
+ bad_stab (orig);
+ return FALSE;
+ }
+
+ ++*pp;
return TRUE;
}
/* Parse a range type. */
static debug_type
-parse_stab_range_type (void *dhandle, struct stab_handle *info, const char *type_name, const char **pp, const int *typenums)
+parse_stab_range_type (void * dhandle,
+ struct stab_handle * info,
+ const char * type_name,
+ const char ** pp,
+ const int * typenums,
+ const char * p_end)
{
const char *orig;
int rangenums[2];
bfd_boolean ov2, ov3;
orig = *pp;
+ if (orig >= p_end)
+ return DEBUG_TYPE_NULL;
index_type = DEBUG_TYPE_NULL;
/* First comes a type we are a subrange of.
In C it is usually 0, 1 or the type being defined. */
- if (! parse_stab_type_number (pp, rangenums))
+ if (! parse_stab_type_number (pp, rangenums, p_end))
return DEBUG_TYPE_NULL;
self_subrange = (rangenums[0] == typenums[0]
{
*pp = orig;
index_type = parse_stab_type (dhandle, info, (const char *) NULL,
- pp, (debug_type **) NULL);
+ pp, (debug_type **) NULL, p_end);
if (index_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
/* The remaining two operands are usually lower and upper bounds of
the range. But in some special cases they mean something else. */
s2 = *pp;
- n2 = parse_number (pp, &ov2);
+ n2 = parse_number (pp, &ov2, p_end);
if (**pp != ';')
{
bad_stab (orig);
++*pp;
s3 = *pp;
- n3 = parse_number (pp, &ov3);
+ n3 = parse_number (pp, &ov3, p_end);
if (**pp != ';')
{
bad_stab (orig);
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))
+ else if (n3 == (bfd_signed_vma) 0xffffffffffffffffLL)
return debug_make_int_type (dhandle, 8, TRUE);
#endif
}
FIXME. */
static debug_type
-parse_stab_sun_builtin_type (void *dhandle, const char **pp)
+parse_stab_sun_builtin_type (void *dhandle, const char **pp, const char * p_end)
{
const char *orig;
bfd_boolean unsignedp;
bfd_vma bits;
orig = *pp;
+ if (orig >= p_end)
+ return DEBUG_TYPE_NULL;
switch (**pp)
{
by this type, except that unsigned short is 4 instead of 2.
Since this information is redundant with the third number,
we will ignore it. */
- (void) parse_number (pp, (bfd_boolean *) NULL);
+ (void) parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
++*pp;
/* The second number is always 0, so ignore it too. */
- (void) parse_number (pp, (bfd_boolean *) NULL);
+ (void) parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
++*pp;
/* The third number is the number of bits for this type. */
- bits = parse_number (pp, (bfd_boolean *) NULL);
+ bits = parse_number (pp, (bfd_boolean *) NULL, p_end);
/* The type *should* end with a semicolon. If it are embedded
in a larger type the semicolon may be the only way to know where
/* Parse a builtin floating type generated by the Sun compiler. */
static debug_type
-parse_stab_sun_floating_type (void *dhandle, const char **pp)
+parse_stab_sun_floating_type (void *dhandle, const char **pp, const char *p_end)
{
const char *orig;
bfd_vma details;
bfd_vma bytes;
orig = *pp;
+ if (orig >= p_end)
+ return DEBUG_TYPE_NULL;
/* The first number has more details about the type, for example
FN_COMPLEX. */
- details = parse_number (pp, (bfd_boolean *) NULL);
+ details = parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
}
/* The second number is the number of bytes occupied by this type */
- bytes = parse_number (pp, (bfd_boolean *) NULL);
+ bytes = parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
/* Handle an enum type. */
static debug_type
-parse_stab_enum_type (void *dhandle, const char **pp)
+parse_stab_enum_type (void *dhandle, const char **pp, const char * p_end)
{
const char *orig;
const char **names;
unsigned int alloc;
orig = *pp;
+ if (orig >= p_end)
+ return DEBUG_TYPE_NULL;
/* FIXME: gdb checks os9k_stabs here. */
my guess is it's a type of some sort. Just ignore it. */
if (**pp == '-')
{
- while (**pp != ':')
+ while (**pp != ':' && **pp != 0)
++*pp;
+
+ if (**pp == 0)
+ {
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+ }
++*pp;
}
bfd_signed_vma val;
p = *pp;
- while (*p != ':')
+ while (*p != ':' && *p != 0)
++p;
+ if (*p == 0)
+ {
+ bad_stab (orig);
+ free (names);
+ free (values);
+ return DEBUG_TYPE_NULL;
+ }
+
name = savestring (*pp, p - *pp);
*pp = p + 1;
- val = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
+ val = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ',')
{
bad_stab (orig);
+ free (name);
+ free (names);
+ free (values);
return DEBUG_TYPE_NULL;
}
++*pp;
*PP will point to "4a:1,0,32;;". */
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)
+parse_stab_struct_type (void * dhandle,
+ struct stab_handle * info,
+ const char * tagname,
+ const char ** pp,
+ bfd_boolean structp,
+ const int * typenums,
+ const char * p_end)
{
- const char *orig;
bfd_vma size;
debug_baseclass *baseclasses;
- debug_field *fields;
+ debug_field *fields = NULL;
bfd_boolean statics;
debug_method *methods;
debug_type vptrbase;
bfd_boolean ownvptr;
- orig = *pp;
-
/* Get the size. */
- size = parse_number (pp, (bfd_boolean *) NULL);
+ size = parse_number (pp, (bfd_boolean *) NULL, p_end);
/* Get the other information. */
- 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)
+ if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses, p_end)
+ || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics, p_end)
+ || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods, p_end)
|| ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase,
- &ownvptr))
- return DEBUG_TYPE_NULL;
+ &ownvptr, p_end))
+ {
+ if (fields != NULL)
+ free (fields);
+ return DEBUG_TYPE_NULL;
+ }
if (! statics
&& baseclasses == NULL
Return TRUE for success, FALSE for failure. */
static bfd_boolean
-parse_stab_baseclasses (void *dhandle, struct stab_handle *info,
- const char **pp, debug_baseclass **retp)
+parse_stab_baseclasses (void * dhandle,
+ struct stab_handle * info,
+ const char ** pp,
+ debug_baseclass ** retp,
+ const char * p_end)
{
const char *orig;
unsigned int c, i;
*retp = NULL;
orig = *pp;
+ if (orig >= p_end)
+ return FALSE;
if (**pp != '!')
{
}
++*pp;
- c = (unsigned int) parse_number (pp, (bfd_boolean *) NULL);
+ c = (unsigned int) parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ',')
{
case '1':
is_virtual = TRUE;
break;
+ case 0:
+ bad_stab (orig);
+ return FALSE;
default:
warn_stab (orig, _("unknown virtual character for baseclass"));
is_virtual = FALSE;
case '2':
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
+ case 0:
+ bad_stab (orig);
+ return FALSE;
default:
warn_stab (orig, _("unknown visibility character for baseclass"));
visibility = DEBUG_VISIBILITY_PUBLIC;
/* The remaining value is the bit offset of the portion of the
object corresponding to this baseclass. Always zero in the
absence of multiple inheritance. */
- bitpos = parse_number (pp, (bfd_boolean *) NULL);
+ bitpos = parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ',')
{
bad_stab (orig);
++*pp;
type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL);
+ (debug_type **) NULL, p_end);
if (type == DEBUG_TYPE_NULL)
return FALSE;
Returns 1 for success, 0 for failure. */
static bfd_boolean
-parse_stab_struct_fields (void *dhandle, struct stab_handle *info,
- const char **pp, debug_field **retp,
- bfd_boolean *staticsp)
+parse_stab_struct_fields (void * dhandle,
+ struct stab_handle * info,
+ const char ** pp,
+ debug_field ** retp,
+ bfd_boolean * staticsp,
+ const char * p_end)
{
const char *orig;
const char *p;
*staticsp = FALSE;
orig = *pp;
+ if (orig >= p_end)
+ return FALSE;
c = 0;
alloc = 10;
if ((*p == '$' || *p == '.') && p[1] != '_')
{
++*pp;
- if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c))
- return FALSE;
+ if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c, p_end))
+ {
+ free (fields);
+ return FALSE;
+ }
++c;
continue;
}
if (p == NULL)
{
bad_stab (orig);
+ free (fields);
return FALSE;
}
break;
if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c,
- staticsp))
+ staticsp, p_end))
return FALSE;
++c;
/* Special GNU C++ name. */
static bfd_boolean
-parse_stab_cpp_abbrev (void *dhandle, struct stab_handle *info,
- const char **pp, debug_field *retp)
+parse_stab_cpp_abbrev (void * dhandle,
+ struct stab_handle * info,
+ const char ** pp,
+ debug_field * retp,
+ const char * p_end)
{
const char *orig;
int cpp_abbrev;
*retp = DEBUG_FIELD_NULL;
orig = *pp;
+ if (orig >= p_end)
+ return FALSE;
if (**pp != 'v')
{
++*pp;
cpp_abbrev = **pp;
+ if (cpp_abbrev == 0)
+ {
+ bad_stab (orig);
+ return FALSE;
+ }
++*pp;
/* At this point, *pp points to something like "22:23=*22...", where
name, and construct the field name. */
context = parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL);
+ (debug_type **) NULL, p_end);
if (context == DEBUG_TYPE_NULL)
return FALSE;
++*pp;
type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL);
+ (debug_type **) NULL, p_end);
if (**pp != ',')
{
bad_stab (orig);
}
++*pp;
- bitpos = parse_number (pp, (bfd_boolean *) NULL);
+ bitpos = parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
/* Parse a single field in a struct or union. */
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)
+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 * p_end)
{
const char *orig;
char *name;
bfd_vma bitsize;
orig = *pp;
+ if (orig >= p_end)
+ return FALSE;
/* FIXME: gdb checks ARM_DEMANGLING here. */
case '2':
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
+ case 0:
+ bad_stab (orig);
+ return FALSE;
default:
warn_stab (orig, _("unknown visibility character for field"));
visibility = DEBUG_VISIBILITY_PUBLIC;
}
type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL);
+ (debug_type **) NULL, p_end);
if (type == DEBUG_TYPE_NULL)
- return FALSE;
+ {
+ free (name);
+ return FALSE;
+ }
if (**pp == ':')
{
if (p == NULL)
{
bad_stab (orig);
+ free (name);
return FALSE;
}
if (**pp != ',')
{
bad_stab (orig);
+ free (name);
return FALSE;
}
++*pp;
- bitpos = parse_number (pp, (bfd_boolean *) NULL);
+ bitpos = parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ',')
{
bad_stab (orig);
+ free (name);
return FALSE;
}
++*pp;
- bitsize = parse_number (pp, (bfd_boolean *) NULL);
+ bitsize = parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
+ free (name);
return FALSE;
}
++*pp;
name (such as `+=') and `.' marks the end of the operator name. */
static bfd_boolean
-parse_stab_members (void *dhandle, struct stab_handle *info,
- const char *tagname, const char **pp,
- const int *typenums, debug_method **retp)
+parse_stab_members (void * dhandle,
+ struct stab_handle * info,
+ const char * tagname,
+ const char ** pp,
+ const int * typenums,
+ debug_method ** retp,
+ const char * p_end)
{
const char *orig;
debug_method *methods;
unsigned int c;
unsigned int alloc;
+ char *name = NULL;
+ debug_method_variant *variants = NULL;
+ char *argtypes = NULL;
*retp = NULL;
orig = *pp;
+ if (orig >= p_end)
+ return FALSE;
alloc = 0;
methods = NULL;
while (**pp != ';')
{
const char *p;
- char *name;
- debug_method_variant *variants;
unsigned int cvars;
unsigned int allocvars;
debug_type look_ahead_type;
if (*p != '.')
{
bad_stab (orig);
- return FALSE;
+ goto fail;
}
name = savestring (*pp, p - *pp);
*pp = p + 1;
{
debug_type type;
bfd_boolean stub;
- char *argtypes;
enum debug_visibility visibility;
bfd_boolean constp, volatilep, staticp;
bfd_vma voffset;
else
{
type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL);
+ (debug_type **) NULL, p_end);
if (type == DEBUG_TYPE_NULL)
- return FALSE;
+ goto fail;
+
if (**pp != ':')
{
bad_stab (orig);
- return FALSE;
+ goto fail;
}
}
if (p == NULL)
{
bad_stab (orig);
- return FALSE;
+ goto fail;
}
stub = FALSE;
case '1':
visibility = DEBUG_VISIBILITY_PROTECTED;
break;
+ case 0:
+ bad_stab (orig);
+ goto fail;
default:
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
case '*':
/* virtual member function, followed by index. The sign
bit is supposedly set to distinguish
- pointers-to-methods from virtual function indicies. */
+ pointers-to-methods from virtual function indices. */
++*pp;
- voffset = parse_number (pp, (bfd_boolean *) NULL);
+ voffset = parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
- return FALSE;
+ goto fail;
}
++*pp;
voffset &= 0x7fffffff;
- if (**pp == ';' || *pp == '\0')
+ if (**pp == ';' || **pp == '\0')
{
/* Must be g++ version 1. */
context = DEBUG_TYPE_NULL;
look_ahead_type = parse_stab_type (dhandle, info,
(const char *) NULL,
pp,
- (debug_type **) NULL);
+ (debug_type **) NULL,
+ p_end);
if (**pp == ':')
{
/* g++ version 1 overloaded methods. */
if (**pp != ';')
{
bad_stab (orig);
- return FALSE;
+ goto fail;
}
++*pp;
}
argtypes string is the mangled form of the argument
types, and the full type and the physical name must be
extracted from them. */
- if (! stub)
- physname = argtypes;
- else
+ physname = argtypes;
+ if (stub)
{
debug_type class_type, return_type;
class_type = stab_find_type (dhandle, info, typenums);
if (class_type == DEBUG_TYPE_NULL)
- return FALSE;
+ goto fail;
return_type = debug_get_return_type (dhandle, type);
if (return_type == DEBUG_TYPE_NULL)
{
bad_stab (orig);
- return FALSE;
+ goto fail;
}
type = parse_stab_argtypes (dhandle, info, class_type, name,
tagname, return_type, argtypes,
constp, volatilep, &physname);
if (type == DEBUG_TYPE_NULL)
- return FALSE;
+ goto fail;
}
if (cvars + 1 >= allocvars)
constp,
volatilep);
if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL)
- return FALSE;
+ goto fail;
++cvars;
}
*retp = methods;
return TRUE;
+
+ fail:
+ if (name != NULL)
+ free (name);
+ if (variants != NULL)
+ free (variants);
+ if (argtypes != NULL)
+ free (argtypes);
+ return FALSE;
}
/* Parse a string representing argument types for a method. Stabs
|| CONST_STRNEQ (argtypes, "__dt"));
is_v3 = argtypes[0] == '_' && argtypes[1] == 'Z';
- if (is_destructor || is_full_physname_constructor || is_v3)
- *pphysname = argtypes;
- else
+ if (!(is_destructor || is_full_physname_constructor || is_v3))
{
unsigned int len;
const char *const_prefix;
&& 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);
+ /* Opname selection is no longer supported by libiberty's demangler. */
+ return DEBUG_TYPE_NULL;
}
+
+ physname = (char *) xmalloc (mangled_name_len);
+ if (is_constructor)
+ physname[0] = '\0';
else
- {
- physname = (char *) xmalloc (mangled_name_len);
- if (is_constructor)
- physname[0] = '\0';
- else
- strcpy (physname, fieldname);
- }
+ strcpy (physname, fieldname);
physname_len = strlen (physname);
strcat (physname, buf);
so we can look for the vptr base class info. */
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)
+parse_stab_tilde_field (void * dhandle,
+ struct stab_handle * info,
+ const char ** pp,
+ const int * typenums,
+ debug_type * retvptrbase,
+ bfd_boolean * retownvptr,
+ const char * p_end)
{
const char *orig;
const char *hold;
*retownvptr = FALSE;
orig = *pp;
-
+ if (orig >= p_end)
+ return FALSE;
+
/* If we are positioned at a ';', then skip it. */
if (**pp == ';')
++*pp;
if (**pp != '~')
return TRUE;
-
++*pp;
if (**pp == '=' || **pp == '+' || **pp == '-')
if (**pp != '%')
return TRUE;
-
++*pp;
hold = *pp;
/* The next number is the type number of the base class (possibly
our own class) which supplies the vtable for this class. */
- if (! parse_stab_type_number (pp, vtypenums))
+ if (! parse_stab_type_number (pp, vtypenums, p_end))
return FALSE;
if (vtypenums[0] == typenums[0]
*pp = hold;
vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL);
+ (debug_type **) NULL, p_end);
for (p = *pp; *p != ';' && *p != '\0'; p++)
;
if (*p != ';')
/* Read a definition of an array type. */
static debug_type
-parse_stab_array_type (void *dhandle, struct stab_handle *info,
- const char **pp, bfd_boolean stringp)
+parse_stab_array_type (void * dhandle,
+ struct stab_handle * info,
+ const char ** pp,
+ bfd_boolean stringp,
+ const char * p_end)
{
const char *orig;
const char *p;
for these, produce a type like float[][]. */
orig = *pp;
+ if (orig >= p_end)
+ return DEBUG_TYPE_NULL;
/* FIXME: gdb checks os9k_stabs here. */
/* If the index type is type 0, we take it as int. */
p = *pp;
- if (! parse_stab_type_number (&p, typenums))
+ if (! parse_stab_type_number (&p, typenums, p_end))
return DEBUG_TYPE_NULL;
+
if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=')
{
index_type = debug_find_named_type (dhandle, "int");
else
{
index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL);
+ (debug_type **) NULL, p_end);
}
if (**pp != ';')
adjustable = FALSE;
- if (! ISDIGIT (**pp) && **pp != '-')
+ if (! ISDIGIT (**pp) && **pp != '-' && **pp != 0)
{
++*pp;
adjustable = TRUE;
}
- lower = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
+ lower = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
}
++*pp;
- if (! ISDIGIT (**pp) && **pp != '-')
+ if (! ISDIGIT (**pp) && **pp != '-' && **pp != 0)
{
++*pp;
adjustable = TRUE;
}
- upper = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
+ upper = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
++*pp;
element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
- (debug_type **) NULL);
+ (debug_type **) NULL, p_end);
if (element_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
return info->main_filename;
info->bincl_stack = o->next_stack;
+ if (o->file >= info->files)
+ return info->main_filename;
+
o->file_types = info->file_types[o->file];
if (info->bincl_stack == NULL)
case 9:
name = "unsigned";
rettype = debug_make_int_type (dhandle, 4, TRUE);
+ break;
case 10:
name = "unsigned long";
rettype = debug_make_int_type (dhandle, 4, TRUE);
ft = debug_get_field_type (minfo->dhandle, *fields);
if (ft == NULL)
- return FALSE;
+ {
+ free (name);
+ return FALSE;
+ }
dn = debug_get_type_name (minfo->dhandle, ft);
if (dn != NULL && strcmp (dn, name) == 0)
{
free (s1);
- s3 = cplus_demangle (s2, DMGL_ANSI);
+ s3 = cplus_demangle (s2, demangle_flags);
free (s2);
case 'M':
case 'O':
{
- bfd_boolean memberp, constp, volatilep;
+ bfd_boolean memberp;
debug_type class_type = DEBUG_TYPE_NULL;
debug_type *args;
bfd_boolean varargs;
const char *name;
memberp = **pp == 'M';
- constp = FALSE;
- volatilep = FALSE;
args = NULL;
varargs = FALSE;
{
if (**pp == 'C')
{
- constp = TRUE;
++*pp;
}
else if (**pp == 'V')
{
- volatilep = TRUE;
++*pp;
}
if (**pp != 'F')
case 'Q':
{
- const char *hold;
-
- hold = *pp;
if (! stab_demangle_qualified (minfo, pp, ptype))
return FALSE;
}
void *mem;
debug_type *pargs;
- dc = cplus_demangle_v3_components (physname, DMGL_PARAMS | DMGL_ANSI, &mem);
+ dc = cplus_demangle_v3_components (physname, DMGL_PARAMS | demangle_flags, &mem);
if (dc == NULL)
{
stab_bad_demangle (physname);
return NULL;
}
+ /* PR 13925: Cope if the demangler returns an empty
+ context for a function with no arguments. */
+ if (dc->u.s_binary.left == NULL)
+ break;
+
arg = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left,
NULL, &varargs);
if (arg == NULL)
/* We print this component to get a class name which we can
use. FIXME: This probably won't work if the template uses
template parameters which refer to an outer template. */
- p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
+ p = cplus_demangle_print (DMGL_PARAMS | demangle_flags, dc, 20, &alc);
if (p == NULL)
{
fprintf (stderr, _("Failed to print demangled template\n"));
/* We print this component in order to find out the type name.
FIXME: Should we instead expose the
demangle_builtin_type_info structure? */
- p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
+ p = cplus_demangle_print (DMGL_PARAMS | demangle_flags, dc, 20, &alc);
if (p == NULL)
{
fprintf (stderr, _("Couldn't get demangled builtin type\n"));