/* stabs.c -- Parse stabs debugging information
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995-2023 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
/* This file contains code which parses stabs debugging information.
The organization of this code is based on the gdb stabs reading
code. The job it does is somewhat different, because it is not
trying to identify the correct address for anything. */
-#include <stdio.h>
-#include <ctype.h>
-
+#include "sysdep.h"
#include "bfd.h"
-#include "bucomm.h"
#include "libiberty.h"
+#include "safe-ctype.h"
#include "demangle.h"
#include "debug.h"
#include "budbg.h"
-
-/* Meaningless definition needs by aout64.h. FIXME. */
-#define BYTES_IN_WORD 4
-
+#include "filenames.h"
#include "aout/aout64.h"
#include "aout/stab_gnu.h"
{
/* The BFD. */
bfd *abfd;
- /* True if this is stabs in sections. */
- boolean sections;
+ /* TRUE if this is stabs in sections. */
+ bool sections;
/* The symbol table. */
asymbol **syms;
/* The number of symbols. */
int gcc_compiled;
/* Whether an N_OPT symbol was seen that was not generated by gcc,
so that we can detect the SunPRO compiler. */
- boolean n_opt_found;
+ bool n_opt_found;
/* The main file name. */
char *main_filename;
- /* A stack of N_BINCL files. */
+ /* A stack of unfinished N_BINCL files. */
struct bincl_file *bincl_stack;
+ /* A list of finished N_BINCL files. */
+ struct bincl_file *bincl_list;
/* Whether we are inside a function or not. */
- boolean within_function;
+ bool within_function;
/* The address of the end of the function, used if we have seen an
N_FUN symbol while in a function. This is -1 if we have not seen
an N_FUN (the normal case). */
debug_type xcoff_types[XCOFF_TYPE_COUNT];
/* Undefined tags. */
struct stab_tag *tags;
+ /* Set by parse_stab_type if it sees a structure defined as a cross
+ reference to itself. Reset by parse_stab_type otherwise. */
+ bool self_crossref;
};
/* A list of these structures is used to hold pending variable
{
/* Next set of slots for this file. */
struct stab_types *next;
+ /* Where the TYPES array starts. */
+ unsigned int base_index;
/* Types indexed by type number. */
#define STAB_TYPES_SLOTS (16)
debug_type types[STAB_TYPES_SLOTS];
debug_type type;
};
-static char *savestring PARAMS ((const char *, int));
-static bfd_vma parse_number PARAMS ((const char **, boolean *));
-static void bad_stab PARAMS ((const char *));
-static void warn_stab PARAMS ((const char *, const char *));
-static boolean parse_stab_string
- PARAMS ((PTR, struct stab_handle *, int, int, bfd_vma, const char *));
+static void bad_stab (const char *);
+static void warn_stab (const char *, const char *);
+static bool parse_stab_string
+ (void *, struct stab_handle *, int, int, bfd_vma,
+ const char *, const char *);
static debug_type parse_stab_type
- PARAMS ((PTR, struct stab_handle *, const char *, const char **,
- debug_type **));
-static boolean parse_stab_type_number
- PARAMS ((const char **, int *));
+ (void *, struct stab_handle *, const char *, const char **,
+ debug_type **, const char *);
+static bool parse_stab_type_number
+ (const char **, int *, const char *);
static debug_type parse_stab_range_type
- PARAMS ((PTR, struct stab_handle *, const char *, const char **,
- const int *));
-static debug_type parse_stab_sun_builtin_type PARAMS ((PTR, 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
- PARAMS ((PTR, const char **));
-static debug_type parse_stab_enum_type PARAMS ((PTR, const char **));
+ (void *, const char **, const char *);
+static debug_type parse_stab_enum_type
+ (void *, const char **, const char *);
static debug_type parse_stab_struct_type
- PARAMS ((PTR, struct stab_handle *, const char *, const char **, boolean,
- const int *));
-static boolean parse_stab_baseclasses
- PARAMS ((PTR, struct stab_handle *, const char **, debug_baseclass **));
-static boolean parse_stab_struct_fields
- PARAMS ((PTR, struct stab_handle *, const char **, debug_field **,
- boolean *));
-static boolean parse_stab_cpp_abbrev
- PARAMS ((PTR, struct stab_handle *, const char **, debug_field *));
-static boolean parse_stab_one_struct_field
- PARAMS ((PTR, struct stab_handle *, const char **, const char *,
- debug_field *, boolean *));
-static boolean parse_stab_members
- PARAMS ((PTR, struct stab_handle *, const char *, const char **,
- const int *, debug_method **));
+ (void *, struct stab_handle *, const char *, const char **,
+ bool, const int *, const char *);
+static bool parse_stab_baseclasses
+ (void *, struct stab_handle *, const char **, debug_baseclass **,
+ const char *);
+static bool parse_stab_struct_fields
+ (void *, struct stab_handle *, const char **, debug_field **,
+ bool *, const char *);
+static bool parse_stab_cpp_abbrev
+ (void *, struct stab_handle *, const char **, debug_field *, const char *);
+static bool parse_stab_one_struct_field
+ (void *, struct stab_handle *, const char **, const char *,
+ debug_field *, bool *, const char *);
+static bool parse_stab_members
+ (void *, struct stab_handle *, const char *, const char **, const int *,
+ debug_method **, const char *);
static debug_type parse_stab_argtypes
- PARAMS ((PTR, struct stab_handle *, debug_type, const char *, const char *,
- debug_type, const char *, boolean, boolean, const char **));
-static boolean parse_stab_tilde_field
- PARAMS ((PTR, struct stab_handle *, const char **, const int *,
- debug_type *, boolean *));
+ (void *, struct stab_handle *, debug_type, const char *, const char *,
+ debug_type, const char *, bool, bool, const char **);
+static bool parse_stab_tilde_field
+ (void *, struct stab_handle *, const char **, const int *, debug_type *,
+ bool *, const char *);
static debug_type parse_stab_array_type
- PARAMS ((PTR, struct stab_handle *, const char **, boolean));
-static void push_bincl PARAMS ((struct stab_handle *, const char *));
-static const char *pop_bincl PARAMS ((struct stab_handle *));
-static boolean stab_record_variable
- PARAMS ((PTR, struct stab_handle *, const char *, debug_type,
- enum debug_var_kind, bfd_vma));
-static boolean stab_emit_pending_vars PARAMS ((PTR, struct stab_handle *));
-static debug_type *stab_find_slot
- PARAMS ((struct stab_handle *, const int *));
-static debug_type stab_find_type
- PARAMS ((PTR, struct stab_handle *, const int *));
-static boolean stab_record_type
- PARAMS ((PTR, struct stab_handle *, const int *, debug_type));
+ (void *, struct stab_handle *, const char **, bool, const char *);
+static void push_bincl (void *, struct stab_handle *, const char *, bfd_vma);
+static const char *pop_bincl (struct stab_handle *);
+static bool find_excl (struct stab_handle *, const char *, bfd_vma);
+static bool stab_record_variable
+ (void *, struct stab_handle *, const char *, debug_type,
+ enum debug_var_kind, bfd_vma);
+static bool stab_emit_pending_vars (void *, struct stab_handle *);
+static debug_type *stab_find_slot (void *, struct stab_handle *, const int *);
+static debug_type stab_find_type (void *, struct stab_handle *, const int *);
+static bool stab_record_type
+ (void *, struct stab_handle *, const int *, debug_type);
static debug_type stab_xcoff_builtin_type
- PARAMS ((PTR, struct stab_handle *, int));
+ (void *, struct stab_handle *, unsigned int);
static debug_type stab_find_tagged_type
- PARAMS ((PTR, struct stab_handle *, const char *, int,
- enum debug_type_kind));
+ (void *, struct stab_handle *, const char *, int, enum debug_type_kind);
static debug_type *stab_demangle_argtypes
- PARAMS ((PTR, struct stab_handle *, const char *, boolean *));
+ (void *, struct stab_handle *, const char *, bool *, unsigned int);
+static debug_type *stab_demangle_v3_argtypes
+ (void *, struct stab_handle *, const char *, bool *);
+static debug_type *stab_demangle_v3_arglist
+ (void *, struct stab_handle *, struct demangle_component *, bool *);
+static debug_type stab_demangle_v3_arg
+ (void *, struct stab_handle *, struct demangle_component *, debug_type,
+ bool *);
+
+static int demangle_flags = DMGL_ANSI;
/* Save a string in memory. */
static char *
-savestring (start, len)
- const char *start;
- int len;
+savestring (void *dhandle, const char *start, size_t len)
{
char *ret;
- ret = (char *) xmalloc (len + 1);
+ ret = debug_xalloc (dhandle, len + 1);
memcpy (ret, start, len);
ret[len] = '\0';
return ret;
/* Read a number from a string. */
static bfd_vma
-parse_number (pp, poverflow)
- const char **pp;
- boolean *poverflow;
+parse_number (const char **pp, bool *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);
if (ul + 1 != 0 || errno == 0)
- return (bfd_vma) ul;
+ {
+ /* If bfd_vma is larger than unsigned long, and the number is
+ meant to be negative, we have to make sure that we sign
+ extend properly. */
+ if (*orig == '-')
+ return (bfd_vma) (bfd_signed_vma) (long) ul;
+ return (bfd_vma) ul;
+ }
/* Note that even though strtoul overflowed, it should have set *pp
to the end of the number, which is where we want it. */
-
if (sizeof (bfd_vma) > sizeof (unsigned long))
{
const char *p;
- boolean neg;
+ bool neg;
int base;
bfd_vma over, lastdig;
- boolean overflow;
+ bool overflow;
bfd_vma v;
/* Our own version of strtoul, for a bfd_vma. */
-
p = orig;
neg = false;
int d;
d = *p++;
- if (isdigit ((unsigned char) d))
+ if (ISDIGIT (d))
d -= '0';
- else if (isupper ((unsigned char) d))
+ else if (ISUPPER (d))
d -= 'A';
- else if (islower ((unsigned char) d))
+ else if (ISLOWER (d))
d -= 'a';
else
break;
/* If we get here, the number is too large to represent in a
bfd_vma. */
-
if (poverflow != NULL)
*poverflow = true;
else
- warn_stab (orig, "numeric overflow");
+ warn_stab (orig, _("numeric overflow"));
return 0;
}
/* Give an error for a bad stab string. */
static void
-bad_stab (p)
- const char *p;
+bad_stab (const char *p)
{
- fprintf (stderr, "Bad stab: %s\n", p);
+ fprintf (stderr, _("Bad stab: %s\n"), p);
}
/* Warn about something in a stab string. */
static void
-warn_stab (p, err)
- const char *p;
- const char *err;
+warn_stab (const char *p, const char *err)
{
- fprintf (stderr, "Warning: %s: %s\n", err, p);
+ fprintf (stderr, _("Warning: %s: %s\n"), err, p);
}
/* Create a handle to parse stabs symbols with. */
-/*ARGSUSED*/
-PTR
-start_stab (dhandle, abfd, sections, syms, symcount)
- PTR dhandle;
- bfd *abfd;
- boolean sections;
- asymbol **syms;
- long symcount;
+void *
+start_stab (void *dhandle ATTRIBUTE_UNUSED, bfd *abfd, bool sections,
+ asymbol **syms, long symcount)
{
struct stab_handle *ret;
- ret = (struct stab_handle *) xmalloc (sizeof *ret);
- memset (ret, 0, sizeof *ret);
+ ret = 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 = xmalloc (sizeof (*ret->file_types));
ret->file_types[0] = NULL;
- ret->function_end = (bfd_vma) -1;
- return (PTR) ret;
+ ret->function_end = -1;
+ return ret;
}
/* When we have processed all the stabs information, we need to go
through and fill in all the undefined tags. */
-boolean
-finish_stab (dhandle, handle)
- PTR dhandle;
- PTR handle;
+bool
+finish_stab (void *dhandle, void *handle, bool emit)
{
struct stab_handle *info = (struct stab_handle *) handle;
struct stab_tag *st;
+ bool ret = true;
- if (info->within_function)
+ if (emit && 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;
+ ret = false;
}
- for (st = info->tags; st != NULL; st = st->next)
- {
- enum debug_type_kind kind;
+ if (emit && ret)
+ 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;
- }
+ 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)
+ {
+ ret = false;
+ break;
+ }
+ }
- return true;
+ free (info->file_types);
+ free (info->so_string);
+ free (info);
+ return ret;
}
/* Handle a single stabs symbol. */
-boolean
-parse_stab (dhandle, handle, type, desc, value, string)
- PTR dhandle;
- PTR handle;
- int type;
- int desc;
- bfd_vma value;
- const char *string;
+bool
+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;
+ char *copy;
+ size_t len;
/* gcc will emit two N_SO strings per compilation unit, one for the
directory name and one for the file name. We just collect N_SO
if (info->so_string != NULL
&& (type != N_SO || *string == '\0' || value != info->so_value))
{
- if (! debug_set_filename (dhandle, info->so_string))
+ len = strlen (info->so_string) + 1;
+ copy = debug_xalloc (dhandle, len);
+ memcpy (copy, info->so_string, len);
+ if (! debug_set_filename (dhandle, copy))
return false;
- info->main_filename = info->so_string;
+ info->main_filename = copy;
+
+ free (info->so_string);
+ info->so_string = NULL;
info->gcc_compiled = 0;
info->n_opt_found = false;
info->file_start_offset = info->so_value;
/* We need to reset the mapping from type numbers to types. We
- can't free the old mapping, because of the use of
- debug_make_indirect_type. */
+ can only free the file_types array, not the stab_types
+ list entries due to the use of debug_make_indirect_type. */
info->files = 1;
- info->file_types = ((struct stab_types **)
- xmalloc (sizeof *info->file_types));
+ info->file_types = xrealloc (info->file_types, 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:
if (! info->within_function)
{
- fprintf (stderr, "N_LBRAC not within function\n");
+ fprintf (stderr, _("N_LBRAC not within function\n"));
return false;
}
--info->block_depth;
if (info->block_depth < 0)
{
- fprintf (stderr, "Too many N_RBRACs\n");
+ fprintf (stderr, _("Too many N_RBRACs\n"));
return false;
}
break;
return true;
/* Just accumulate strings until we see a non N_SO symbol. If
- the string starts with '/', we discard the previously
+ the string starts with a directory separator or some other
+ form of absolute path specification, we discard the previously
accumulated strings. */
if (info->so_string == NULL)
info->so_string = xstrdup (string);
char *f;
f = info->so_string;
- if (*string == '/')
+
+ if (IS_ABSOLUTE_PATH (string))
info->so_string = xstrdup (string);
else
info->so_string = concat (info->so_string, string,
case N_SOL:
/* Start an include file. */
- if (! debug_start_source (dhandle, string))
+ len = strlen (string) + 1;
+ copy = debug_xalloc (dhandle, len);
+ memcpy (copy, string, len);
+ if (! debug_start_source (dhandle, copy))
return false;
break;
case N_BINCL:
/* Start an include file which may be replaced. */
- push_bincl (info, string);
- if (! debug_start_source (dhandle, string))
+ len = strlen (string) + 1;
+ copy = debug_xalloc (dhandle, len);
+ memcpy (copy, string, len);
+ push_bincl (dhandle, info, copy, value);
+ if (! debug_start_source (dhandle, copy))
return false;
break;
case N_EXCL:
/* This is a duplicate of a header file named by N_BINCL which
was eliminated by the linker. */
- ++info->files;
- info->file_types = ((struct stab_types **)
- xrealloc ((PTR) info->file_types,
- (info->files
- * sizeof *info->file_types)));
- info->file_types[info->files - 1] = NULL;
+ if (! find_excl (info, string, value))
+ return false;
break;
case N_SLINE:
if (! debug_record_line (dhandle, desc,
- value + info->function_start_offset))
+ value + (info->within_function
+ ? info->function_start_offset : 0)))
return false;
break;
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;
case N_OBJ:
case N_ENDM:
case N_MAIN:
+ case N_WARNING:
break;
}
/* Parse the stabs string. */
-static boolean
-parse_stab_string (dhandle, info, stabtype, desc, value, string)
- PTR dhandle;
- struct stab_handle *info;
- int stabtype;
- int desc;
- bfd_vma value;
- const char *string;
+static bool
+parse_stab_string (void *dhandle, struct stab_handle *info, int stabtype,
+ int desc ATTRIBUTE_UNUSED, bfd_vma value,
+ const char *string, const char * string_end)
{
const char *p;
char *name;
int type;
debug_type dtype;
- boolean synonym;
- unsigned int lineno;
+ bool synonym;
+ bool self_crossref;
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] == '$')
/* SunPRO (3.0 at least) static variable encoding. */
break;
default:
- warn_stab (string, "unknown C++ encoded name");
+ warn_stab (string, _("unknown C++ encoded name"));
break;
}
}
if (p == string || (string[0] == ' ' && p == string + 1))
name = NULL;
else
- name = savestring (string, p - string);
+ name = savestring (dhandle, string, p - string);
}
++p;
- if (isdigit ((unsigned char) *p) || *p == '(' || *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;
address on a big endian machine if it is smaller than an int.
We have no way to do that, since we don't really know much
about the target. */
-
break;
case 'P':
{
++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,
/* FIXME: At this point gdb checks to combine pairs of 'p' and
'r' stabs into a single 'P' stab. */
-
break;
case 'S':
- /* Static symbol at top level of file */
+ /* 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')
{
synonym = false;
- /* FIXME: gdb sets synonym to true if the current language
+ /* FIXME: gdb sets synonym to TRUE if the current language
is C++. */
}
else
++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)
return true;
+ /* INFO->SELF_CROSSREF is set by parse_stab_type if this type is
+ a cross reference to itself. These are generated by some
+ versions of g++. */
+ self_crossref = info->self_crossref;
+
dtype = debug_tag_type (dhandle, name, dtype);
if (dtype == DEBUG_TYPE_NULL)
return false;
*slot = dtype;
/* See if we have a cross reference to this tag which we can now
- fill in. */
- {
- register struct stab_tag **pst;
+ fill in. Avoid filling in a cross reference to ourselves,
+ because that would lead to circular debugging information. */
+ 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;
- }
- }
- }
+ 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)
{
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,
return false;
break;
+ case 'Y':
+ /* SUNPro C++ Namespace =Yn0. */
+ /* Skip the namespace mapping, as it is not used now. */
+ if (*p++ != 0 && *p++ == 'n' && *p++ == '0')
+ {
+ /* =Yn0name; */
+ while (*p && *p != ';')
+ ++p;
+ if (*p)
+ return true;
+ }
+ /* TODO SUNPro C++ support:
+ Support default arguments after F,P parameters
+ Ya = Anonymous unions
+ YM,YD = Pointers to class members
+ YT,YI = Templates
+ YR = Run-time type information (RTTI) */
+
+ /* Fall through. */
+
default:
bad_stab (string);
return false;
store the slot used if the type is being defined. */
static debug_type
-parse_stab_type (dhandle, info, typename, pp, slotp)
- PTR dhandle;
- struct stab_handle *info;
- const char *typename;
- 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];
int size;
- boolean stringp;
+ bool stringp;
int descriptor;
debug_type dtype;
*slotp = NULL;
orig = *pp;
+ if (orig >= p_end)
+ return DEBUG_TYPE_NULL;
size = -1;
stringp = false;
+ info->self_crossref = false;
+
/* Read type number if present. The type number may be omitted.
for instance in a two-dimensional array declared with type
"ar1;1;10;ar1;1;10;4". */
- if (! isdigit ((unsigned char) **pp) && **pp != '(' && **pp != '-')
+ if (! ISDIGIT (**pp) && **pp != '(' && **pp != '-')
{
/* 'typenums=' not present, type is anonymous. Read and return
the definition, but don't put it in the type vector. */
}
else
{
- if (! parse_stab_type_number (pp, typenums))
+ if (! parse_stab_type_number (pp, typenums, p_end))
return DEBUG_TYPE_NULL;
if (**pp != '=')
- {
- /* Type is not being defined here. Either it already
- exists, or this is a forward reference to it. */
- return stab_find_type (dhandle, info, typenums);
- }
+ /* Type is not being defined here. Either it already
+ exists, or this is a forward reference to it. */
+ return stab_find_type (dhandle, info, typenums);
/* Only set the slot if the type is being defined. This means
that the mapping from type numbers to types will only record
the stabs information records both i and j as having the same
type. This could be fixed by patching the compiler. */
if (slotp != NULL && typenums[0] >= 0 && typenums[1] >= 0)
- *slotp = stab_find_slot (info, typenums);
+ *slotp = stab_find_slot (dhandle, info, typenums);
/* Type is being defined here. */
/* Skip the '='. */
const char *p = *pp + 1;
const char *attr;
- if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-')
- {
- /* Member type. */
- break;
- }
+ if (ISDIGIT (*p) || *p == '(' || *p == '-')
+ /* Member type. */
+ break;
/* Type attributes. */
attr = p;
{
case 's':
size = atoi (attr + 1);
+ size /= 8; /* Size is in bits. We store it in bytes. */
if (size <= 0)
size = -1;
break;
stringp = true;
break;
+ case 0:
+ bad_stab (orig);
+ return DEBUG_TYPE_NULL;
+
default:
/* Ignore unrecognized type attributes, so future
compilers can invent new ones. */
const char *q1, *q2, *p;
/* A cross reference to another type. */
-
switch (**pp)
{
case 's':
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. */
- warn_stab (orig, "unrecognized cross reference type");
+ warn_stab (orig, _("unrecognized cross reference type"));
code = DEBUG_KIND_STRUCT;
break;
}
bad_stab (orig);
return DEBUG_TYPE_NULL;
}
- while (q1 != NULL && p > q1 && p[1] == ':')
+ if (q1 != NULL && p > q1 && p[1] == ':')
{
- q2 = strchr (q1, '>');
- if (q2 == NULL || q2 < p)
- break;
- p += 2;
- p = strchr (p, ':');
- if (p == NULL)
+ 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;
}
}
+ /* Some versions of g++ can emit stabs like
+ fleep:T20=xsfleep:
+ which define structures in terms of themselves. We need to
+ tell the caller to avoid building a circular structure. */
+ if (type_name != NULL
+ && strncmp (type_name, *pp, p - *pp) == 0
+ && type_name[p - *pp] == '\0')
+ info->self_crossref = true;
+
dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code);
*pp = p + 1;
int xtypenums[2];
/* This type is defined as another type. */
-
(*pp)--;
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 != ';')
{
debug_type domain;
debug_type return_type;
- debug_type *args;
+ debug_type *args, *xargs;
unsigned int n;
unsigned int alloc;
- boolean varargs;
+ bool 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;
alloc = 10;
- args = (debug_type *) xmalloc (alloc * sizeof *args);
+ args = xmalloc (alloc * sizeof (*args));
n = 0;
while (**pp != ';')
{
if (**pp != ',')
{
bad_stab (orig);
+ free (args);
return DEBUG_TYPE_NULL;
}
++*pp;
if (n + 1 >= alloc)
{
alloc += 10;
- args = ((debug_type *)
- xrealloc ((PTR) args, alloc * sizeof *args));
+ args = xrealloc (args, alloc * sizeof (*args));
}
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;
+ {
+ free (args);
+ return DEBUG_TYPE_NULL;
+ }
++n;
}
++*pp;
}
args[n] = DEBUG_TYPE_NULL;
+ xargs = debug_xalloc (dhandle, (n + 1) * sizeof (*args));
+ memcpy (xargs, args, (n + 1) * sizeof (*args));
+ free (args);
- dtype = debug_make_method_type (dhandle, return_type, domain, args,
+ dtype = debug_make_method_type (dhandle, return_type, domain, xargs,
varargs);
}
break;
case 'r':
/* Range type. */
- dtype = parse_stab_range_type (dhandle, info, typename, 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, typename, pp,
- descriptor == 's', typenums);
+ dtype = parse_stab_struct_type (dhandle, info, type_name, pp,
+ 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;
if (size != -1)
{
if (! debug_record_type_size (dhandle, dtype, (unsigned int) size))
- return false;
+ return DEBUG_TYPE_NULL;
}
return dtype;
single number N is equivalent to (0,N). Return the two numbers by
storing them in the vector TYPENUMS. */
-static boolean
-parse_stab_type_number (pp, typenums)
- const char **pp;
- int *typenums;
+static bool
+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, (boolean *) NULL);
+ typenums[1] = (int) parse_number (pp, (bool *) NULL, p_end);
+ return true;
}
- else
+
+ ++*pp;
+ typenums[0] = (int) parse_number (pp, (bool *) NULL, p_end);
+ if (**pp != ',')
{
- ++*pp;
- typenums[0] = (int) parse_number (pp, (boolean *) NULL);
- if (**pp != ',')
- {
- bad_stab (orig);
- return false;
- }
- ++*pp;
- typenums[1] = (int) parse_number (pp, (boolean *) NULL);
- if (**pp != ')')
- {
- bad_stab (orig);
- return false;
- }
- ++*pp;
+ bad_stab (orig);
+ return false;
+ }
+
+ ++*pp;
+ typenums[1] = (int) parse_number (pp, (bool *) NULL, p_end);
+ if (**pp != ')')
+ {
+ bad_stab (orig);
+ return false;
}
+ ++*pp;
return true;
}
/* Parse a range type. */
static debug_type
-parse_stab_range_type (dhandle, info, typename, pp, typenums)
- PTR dhandle;
- struct stab_handle *info;
- const char *typename;
- 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];
- boolean self_subrange;
+ bool self_subrange;
debug_type index_type;
const char *s2, *s3;
bfd_signed_vma n2, n3;
- boolean ov2, ov3;
+ bool 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);
{
/* gcc will emit range stabs for long long types. Handle this
as a special case. FIXME: This needs to be more general. */
-#define LLLOW "01000000000000000000000;"
-#define LLHIGH "0777777777777777777777;"
+#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)
+ if (startswith (s2, LLLOW)
+ && startswith (s3, LLHIGH))
return debug_make_int_type (dhandle, 8, false);
if (! ov2
&& n2 == 0
- && strncmp (s3, ULLHIGH, sizeof ULLHIGH - 1) == 0)
+ && startswith (s3, ULLHIGH))
return debug_make_int_type (dhandle, 8, true);
}
- warn_stab (orig, "numeric overflow");
+ warn_stab (orig, _("numeric overflow"));
}
if (index_type == DEBUG_TYPE_NULL)
long long int:t6=r1;0;-1;
long long unsigned int:t7=r1;0;-1;
We hack here to handle this reasonably. */
- if (typename != NULL)
+ if (type_name != NULL)
{
- if (strcmp (typename, "long long int") == 0)
+ if (strcmp (type_name, "long long int") == 0)
return debug_make_int_type (dhandle, 8, false);
- else if (strcmp (typename, "long long unsigned int") == 0)
+ else if (strcmp (type_name, "long long unsigned int") == 0)
return debug_make_int_type (dhandle, 8, true);
}
/* FIXME: The size here really depends upon the target. */
return debug_make_int_type (dhandle, 1, true);
else if (n3 == 0xffff)
return debug_make_int_type (dhandle, 2, true);
- /* -1 is used for the upper bound of (4 byte) "unsigned int"
- and "unsigned long", and we already checked for that, so
- don't need to test for it here. */
+ else if (n3 == (bfd_signed_vma) 0xffffffff)
+ return debug_make_int_type (dhandle, 4, true);
+#ifdef BFD64
+ else if (n3 == (bfd_signed_vma) 0xffffffffffffffffLL)
+ 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)
+ else if (n2 == - n3 - 1 || n2 == n3 + 1)
{
if (n3 == 0x7f)
return debug_make_int_type (dhandle, 1, false);
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
}
}
{
/* Does this actually ever happen? Is that why we are worrying
about dealing with it rather than just calling error_type? */
- warn_stab (orig, "missing index type");
+ warn_stab (orig, _("missing index type"));
index_type = debug_make_int_type (dhandle, 4, false);
}
FIXME. */
static debug_type
-parse_stab_sun_builtin_type (dhandle, pp)
- PTR dhandle;
- const char **pp;
+parse_stab_sun_builtin_type (void *dhandle, const char **pp, const char * p_end)
{
const char *orig;
- boolean unsignedp;
+ bool unsignedp;
bfd_vma bits;
orig = *pp;
+ if (orig >= p_end)
+ return DEBUG_TYPE_NULL;
switch (**pp)
{
}
++*pp;
- /* For some odd reason, all forms of char put a c here. This is strange
- because no other type has this honor. We can safely ignore this because
- we actually determine 'char'acterness by the number of bits specified in
- the descriptor. */
- if (**pp == 'c')
+ /* OpenSolaris source code indicates that one of "cbv" characters
+ can come next and specify the intrinsic 'iformat' encoding.
+ 'c' is character encoding, 'b' is boolean encoding, and 'v' is
+ varargs encoding. This field can be safely ignored because
+ the type of the field is determined from the bitwidth extracted
+ below. */
+ if (**pp == 'c' || **pp == 'b' || **pp == 'v')
++*pp;
/* The first number appears to be the number of bytes occupied
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, (boolean *) NULL);
+ (void) parse_number (pp, (bool *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
}
++*pp;
- /* The second number is always 0, so ignore it too. */
- (void) parse_number (pp, (boolean *) NULL);
+ /* The second number is always 0, so ignore it too. */
+ (void) parse_number (pp, (bool *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
}
++*pp;
- /* The third number is the number of bits for this type. */
- bits = parse_number (pp, (boolean *) NULL);
+ /* The third number is the number of bits for this type. */
+ bits = parse_number (pp, (bool *) 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 (dhandle, pp)
- PTR 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, (boolean *) NULL);
+ details = parse_number (pp, (bool *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
}
/* The second number is the number of bytes occupied by this type */
- bytes = parse_number (pp, (boolean *) NULL);
+ bytes = parse_number (pp, (bool *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
|| details == NF_COMPLEX32)
return debug_make_complex_type (dhandle, bytes);
- return debug_make_float_type (dhandle, bytes);
+ return debug_make_float_type (dhandle, bytes);
}
/* Handle an enum type. */
static debug_type
-parse_stab_enum_type (dhandle, pp)
- PTR dhandle;
- const char **pp;
+parse_stab_enum_type (void *dhandle, const char **pp, const char * p_end)
{
const char *orig;
- const char **names;
- bfd_signed_vma *values;
+ const char **names, **xnames;
+ bfd_signed_vma *values, *xvalues;
unsigned int n;
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;
}
The input syntax is NAME:VALUE,NAME:VALUE, and so on.
A semicolon or comma instead of a NAME means the end. */
alloc = 10;
- names = (const char **) xmalloc (alloc * sizeof *names);
- values = (bfd_signed_vma *) xmalloc (alloc * sizeof *values);
+ names = xmalloc (alloc * sizeof (*names));
+ values = xmalloc (alloc * sizeof (*values));
n = 0;
while (**pp != '\0' && **pp != ';' && **pp != ',')
{
bfd_signed_vma val;
p = *pp;
- while (*p != ':')
+ while (*p != ':' && *p != 0)
++p;
- name = savestring (*pp, p - *pp);
+ if (*p == 0)
+ {
+ bad_stab (orig);
+ free (names);
+ free (values);
+ return DEBUG_TYPE_NULL;
+ }
+
+ name = savestring (dhandle, *pp, p - *pp);
*pp = p + 1;
- val = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
+ val = (bfd_signed_vma) parse_number (pp, (bool *) NULL, p_end);
if (**pp != ',')
{
bad_stab (orig);
+ free (names);
+ free (values);
return DEBUG_TYPE_NULL;
}
++*pp;
if (n + 1 >= alloc)
{
alloc += 10;
- names = ((const char **)
- xrealloc ((PTR) names, alloc * sizeof *names));
- values = ((bfd_signed_vma *)
- xrealloc ((PTR) values, alloc * sizeof *values));
+ names = xrealloc (names, alloc * sizeof (*names));
+ values = xrealloc (values, alloc * sizeof (*values));
}
names[n] = name;
names[n] = NULL;
values[n] = 0;
+ xnames = debug_xalloc (dhandle, (n + 1) * sizeof (*names));
+ memcpy (xnames, names, (n + 1) * sizeof (*names));
+ free (names);
+ xvalues = debug_xalloc (dhandle, (n + 1) * sizeof (*names));
+ memcpy (xvalues, values, (n + 1) * sizeof (*names));
+ free (values);
if (**pp == ';')
++*pp;
- return debug_make_enum_type (dhandle, names, values);
+ return debug_make_enum_type (dhandle, xnames, xvalues);
}
/* Read the description of a structure (or union type) and return an object
describing the type.
PP points to a character pointer that points to the next unconsumed token
- in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;",
+ in the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;",
*PP will point to "4a:1,0,32;;". */
static debug_type
-parse_stab_struct_type (dhandle, info, tagname, pp, structp, typenums)
- PTR dhandle;
- struct stab_handle *info;
- const char *tagname;
- const char **pp;
- boolean structp;
- const int *typenums;
+parse_stab_struct_type (void *dhandle,
+ struct stab_handle *info,
+ const char *tagname,
+ const char **pp,
+ bool structp,
+ const int *typenums,
+ const char *p_end)
{
- const char *orig;
bfd_vma size;
debug_baseclass *baseclasses;
- debug_field *fields;
- boolean statics;
+ debug_field *fields = NULL;
+ bool statics;
debug_method *methods;
debug_type vptrbase;
- boolean ownvptr;
-
- orig = *pp;
+ bool ownvptr;
/* Get the size. */
- size = parse_number (pp, (boolean *) NULL);
+ size = parse_number (pp, (bool *) 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))
+ &ownvptr, p_end))
return DEBUG_TYPE_NULL;
if (! statics
the type for the base class, and a terminating semicolon.
A typical example, with two base classes, would be "!2,020,19;0264,21;".
- ^^ ^ ^ ^ ^ ^ ^
+ ^^ ^ ^ ^ ^ ^ ^
Baseclass information marker __________________|| | | | | | |
Number of baseclasses __________________________| | | | | | |
Visibility specifiers (2) ________________________| | | | | |
Offset in bits from start of class ________________________| |
Type number of base class ____________________________________|
- Return true for success, false for failure. */
+ Return TRUE for success, FALSE for failure. */
-static boolean
-parse_stab_baseclasses (dhandle, info, pp, retp)
- PTR dhandle;
- struct stab_handle *info;
- const char **pp;
- debug_baseclass **retp;
+static bool
+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, (boolean *) NULL);
+ c = (unsigned int) parse_number (pp, (bool *) NULL, p_end);
if (**pp != ',')
{
}
++*pp;
- classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp));
+ classes = debug_xalloc (dhandle, (c + 1) * sizeof (*classes));
for (i = 0; i < c; i++)
{
- boolean virtual;
+ bool is_virtual;
enum debug_visibility visibility;
bfd_vma bitpos;
debug_type type;
switch (**pp)
{
case '0':
- virtual = false;
+ is_virtual = false;
break;
case '1':
- virtual = true;
+ is_virtual = true;
break;
+ case 0:
+ bad_stab (orig);
+ return false;
default:
- warn_stab (orig, "unknown virtual character for baseclass");
- virtual = false;
+ warn_stab (orig, _("unknown virtual character for baseclass"));
+ is_virtual = false;
break;
}
++*pp;
case '2':
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
+ case 0:
+ bad_stab (orig);
+ return false;
default:
- warn_stab (orig, "unknown visibility character for baseclass");
+ warn_stab (orig, _("unknown visibility character for baseclass"));
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
}
/* 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, (boolean *) NULL);
+ bitpos = parse_number (pp, (bool *) 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;
- classes[i] = debug_make_baseclass (dhandle, type, bitpos, virtual,
+ classes[i] = debug_make_baseclass (dhandle, type, bitpos, is_virtual,
visibility);
if (classes[i] == DEBUG_BASECLASS_NULL)
return false;
/* Read struct or class data fields. They have the form:
- NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
+ NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
At the end, we see a semicolon instead of a field.
The optional VISIBILITY is one of:
- '/0' (VISIBILITY_PRIVATE)
+ '/0' (VISIBILITY_PRIVATE)
'/1' (VISIBILITY_PROTECTED)
'/2' (VISIBILITY_PUBLIC)
'/9' (VISIBILITY_IGNORE)
Returns 1 for success, 0 for failure. */
-static boolean
-parse_stab_struct_fields (dhandle, info, pp, retp, staticsp)
- PTR dhandle;
- struct stab_handle *info;
- const char **pp;
- debug_field **retp;
- boolean *staticsp;
+static bool
+parse_stab_struct_fields (void *dhandle,
+ struct stab_handle *info,
+ const char **pp,
+ debug_field **retp,
+ bool *staticsp,
+ const char * p_end)
{
const char *orig;
const char *p;
- debug_field *fields;
+ debug_field *fields, *xfields;
unsigned int c;
unsigned int alloc;
*staticsp = false;
orig = *pp;
+ if (orig >= p_end)
+ return false;
c = 0;
alloc = 10;
- fields = (debug_field *) xmalloc (alloc * sizeof *fields);
+ fields = xmalloc (alloc * sizeof (*fields));
while (**pp != ';')
{
/* FIXME: gdb checks os9k_stabs here. */
if (c + 1 >= alloc)
{
alloc += 10;
- fields = ((debug_field *)
- xrealloc ((PTR) fields, alloc * sizeof *fields));
+ fields = xrealloc (fields, alloc * sizeof (*fields));
}
/* If it starts with CPLUS_MARKER it is a special abbreviation,
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;
}
/* Look for the ':' that separates the field name from the field
values. Data members are delimited by a single ':', while member
functions are delimited by a pair of ':'s. When we hit the member
- functions (if any), terminate scan loop and return. */
+ functions (if any), terminate scan loop and return. */
p = strchr (p, ':');
if (p == NULL)
{
bad_stab (orig);
+ free (fields);
return false;
}
break;
if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c,
- staticsp))
- return false;
+ staticsp, p_end))
+ {
+ free (fields);
+ return false;
+ }
++c;
}
fields[c] = DEBUG_FIELD_NULL;
+ xfields = debug_xalloc (dhandle, (c + 1) * sizeof (*fields));
+ memcpy (xfields, fields, (c + 1) * sizeof (*fields));
+ free (fields);
- *retp = fields;
+ *retp = xfields;
return true;
}
/* Special GNU C++ name. */
-static boolean
-parse_stab_cpp_abbrev (dhandle, info, pp, retp)
- PTR dhandle;
- struct stab_handle *info;
- const char **pp;
- debug_field *retp;
+static bool
+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;
debug_type context;
const char *name;
- const char *typename;
+ const char *type_name;
debug_type type;
bfd_vma bitpos;
+ size_t len;
*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;
break;
case 'b':
/* $vb -- a virtual bsomethingorother */
- typename = debug_get_type_name (dhandle, context);
- if (typename == NULL)
+ type_name = debug_get_type_name (dhandle, context);
+ if (type_name == NULL)
{
- warn_stab (orig, "unnamed $vb type");
- typename = "FOO";
+ warn_stab (orig, _("unnamed $vb type"));
+ type_name = "FOO";
}
- name = concat ("_vb$", typename, (const char *) NULL);
+ len = strlen (type_name);
+ name = debug_xalloc (dhandle, len + sizeof ("_vb$"));
+ memcpy ((char *) name, "_vb$", sizeof ("_vb$") - 1);
+ memcpy ((char *) name + sizeof ("_vb$") - 1, type_name, len + 1);
break;
default:
- warn_stab (orig, "unrecognized C++ abbreviation");
+ warn_stab (orig, _("unrecognized C++ abbreviation"));
name = "INVALID_CPLUSPLUS_ABBREV";
break;
}
++*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, (boolean *) NULL);
+ bitpos = parse_number (pp, (bool *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
/* Parse a single field in a struct or union. */
-static boolean
-parse_stab_one_struct_field (dhandle, info, pp, p, retp, staticsp)
- PTR dhandle;
- struct stab_handle *info;
- const char **pp;
- const char *p;
- debug_field *retp;
- boolean *staticsp;
+static bool
+parse_stab_one_struct_field (void *dhandle,
+ struct stab_handle *info,
+ const char **pp,
+ const char *p,
+ debug_field *retp,
+ bool *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. */
- name = savestring (*pp, p - *pp);
+ name = savestring (dhandle, *pp, p - *pp);
*pp = p + 1;
case '2':
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
+ case 0:
+ bad_stab (orig);
+ return false;
default:
- warn_stab (orig, "unknown visibility character for field");
+ warn_stab (orig, _("unknown visibility character for field"));
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
}
}
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;
return false;
}
- varname = savestring (*pp, p - *pp);
+ varname = savestring (dhandle, *pp, p - *pp);
*pp = p + 1;
}
++*pp;
- bitpos = parse_number (pp, (boolean *) NULL);
+ bitpos = parse_number (pp, (bool *) NULL, p_end);
if (**pp != ',')
{
bad_stab (orig);
}
++*pp;
- bitsize = parse_number (pp, (boolean *) NULL);
+ bitsize = parse_number (pp, (bool *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
$ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator
name (such as `+=') and `.' marks the end of the operator name. */
-static boolean
-parse_stab_members (dhandle, info, tagname, pp, typenums, retp)
- PTR dhandle;
- struct stab_handle *info;
- const char *tagname;
- const char **pp;
- const int *typenums;
- debug_method **retp;
+static bool
+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;
+ debug_method *methods, *xmethods;
unsigned int c;
unsigned int alloc;
+ char *name = NULL;
+ debug_method_variant *variants = NULL, *xvariants;
+ 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;
/* FIXME: Some systems use something other than '$' here. */
if ((*pp)[0] != 'o' || (*pp)[1] != 'p' || (*pp)[2] != '$')
{
- name = savestring (*pp, p - *pp);
+ name = savestring (dhandle, *pp, p - *pp);
*pp = p + 2;
}
else
{
- /* This is a completely wierd case. In order to stuff in the
+ /* This is a completely weird case. In order to stuff in the
names that might contain colons (the usual name delimiter),
Mike Tiemann defined a different name format which is
signalled if the identifier is "op$". In that case, the
if (*p != '.')
{
bad_stab (orig);
- return false;
+ goto fail;
}
- name = savestring (*pp, p - *pp);
+ name = savestring (dhandle, *pp, p - *pp);
*pp = p + 1;
}
allocvars = 10;
- variants = ((debug_method_variant *)
- xmalloc (allocvars * sizeof *variants));
+ variants = xmalloc (allocvars * sizeof (*variants));
cvars = 0;
look_ahead_type = DEBUG_TYPE_NULL;
do
{
debug_type type;
- boolean stub;
- char *argtypes;
+ bool stub;
enum debug_visibility visibility;
- boolean constp, volatilep, staticp;
+ bool constp, volatilep, staticp;
bfd_vma voffset;
debug_type context;
const char *physname;
- boolean varargs;
+ bool varargs;
if (look_ahead_type != DEBUG_TYPE_NULL)
{
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;
&& debug_get_parameter_types (dhandle, type, &varargs) == NULL)
stub = true;
- argtypes = savestring (*pp, p - *pp);
+ argtypes = savestring (dhandle, *pp, p - *pp);
*pp = p + 1;
switch (**pp)
case '1':
visibility = DEBUG_VISIBILITY_PROTECTED;
break;
+ case 0:
+ bad_stab (orig);
+ goto fail;
default:
visibility = DEBUG_VISIBILITY_PUBLIC;
break;
/* File compiled with g++ version 1; no information. */
break;
default:
- warn_stab (orig, "const/volatile indicator missing");
+ warn_stab (orig, _("const/volatile indicator missing"));
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, (boolean *) NULL);
+ voffset = parse_number (pp, (bool *) 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;
/* Figure out from whence this virtual function
came. It may belong to virtual function table of
one of its baseclasses. */
- look_ahead_type = parse_stab_type (dhandle, info,
- (const char *) NULL,
- pp,
- (debug_type **) NULL);
- if (**pp == ':')
- {
- /* g++ version 1 overloaded methods. */
- context = DEBUG_TYPE_NULL;
- }
- else
- {
- context = look_ahead_type;
- look_ahead_type = DEBUG_TYPE_NULL;
- if (**pp != ';')
- {
- bad_stab (orig);
- return false;
- }
- ++*pp;
- }
- }
+ look_ahead_type = parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
+ (debug_type **) NULL,
+ p_end);
+ if (**pp == ':')
+ {
+ /* g++ version 1 overloaded methods. */
+ context = DEBUG_TYPE_NULL;
+ }
+ else
+ {
+ context = look_ahead_type;
+ look_ahead_type = DEBUG_TYPE_NULL;
+ if (**pp != ';')
+ {
+ bad_stab (orig);
+ goto fail;
+ }
+ ++*pp;
+ }
+ }
break;
case '?':
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)
{
allocvars += 10;
- variants = ((debug_method_variant *)
- xrealloc ((PTR) variants,
- allocvars * sizeof *variants));
+ variants = xrealloc (variants, allocvars * sizeof (*variants));
}
if (! staticp)
constp,
volatilep);
if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL)
- return false;
+ goto fail;
++cvars;
}
while (**pp != ';' && **pp != '\0');
variants[cvars] = DEBUG_METHOD_VARIANT_NULL;
+ xvariants = debug_xalloc (dhandle, (cvars + 1) * sizeof (*variants));
+ memcpy (xvariants, variants, (cvars + 1) * sizeof (*variants));
+ free (variants);
if (**pp != '\0')
++*pp;
if (c + 1 >= alloc)
{
alloc += 10;
- methods = ((debug_method *)
- xrealloc ((PTR) methods, alloc * sizeof *methods));
+ methods = xrealloc (methods, alloc * sizeof (*methods));
}
- methods[c] = debug_make_method (dhandle, name, variants);
+ methods[c] = debug_make_method (dhandle, name, xvariants);
++c;
}
+ xmethods = methods;
if (methods != NULL)
- methods[c] = DEBUG_METHOD_NULL;
+ {
+ methods[c] = DEBUG_METHOD_NULL;
+ xmethods = debug_xalloc (dhandle, (c + 1) * sizeof (*methods));
+ memcpy (xmethods, methods, (c + 1) * sizeof (*methods));
+ free (methods);
+ }
- *retp = methods;
+ *retp = xmethods;
return true;
+
+ fail:
+ free (variants);
+ free (methods);
+ return false;
}
/* Parse a string representing argument types for a method. Stabs
the tag name. */
static debug_type
-parse_stab_argtypes (dhandle, info, class_type, fieldname, tagname,
- return_type, argtypes, constp, volatilep, pphysname)
- PTR dhandle;
- struct stab_handle *info;
- debug_type class_type;
- const char *fieldname;
- const char *tagname;
- debug_type return_type;
- const char *argtypes;
- boolean constp;
- boolean volatilep;
- const char **pphysname;
+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, bool constp,
+ bool volatilep, const char **pphysname)
{
- boolean is_full_physname_constructor;
- boolean is_constructor;
- boolean is_destructor;
+ bool is_full_physname_constructor;
+ bool is_constructor;
+ bool is_destructor;
+ bool is_v3;
debug_type *args;
- boolean varargs;
+ bool varargs;
+ unsigned int physname_len = 0;
/* Constructors are sometimes handled specially. */
is_full_physname_constructor = ((argtypes[0] == '_'
&& argtypes[1] == '_'
- && (isdigit ((unsigned char) argtypes[2])
+ && (ISDIGIT (argtypes[2])
|| argtypes[2] == 'Q'
|| argtypes[2] == 't'))
- || strncmp (argtypes, "__ct", 4) == 0);
+ || startswith (argtypes, "__ct"));
is_constructor = (is_full_physname_constructor
|| (tagname != NULL
is_destructor = ((argtypes[0] == '_'
&& (argtypes[1] == '$' || argtypes[1] == '.')
&& argtypes[2] == '_')
- || strncmp (argtypes, "__dt", 4) == 0);
+ || startswith (argtypes, "__dt"));
+ is_v3 = argtypes[0] == '_' && argtypes[1] == 'Z';
- if (is_destructor || is_full_physname_constructor)
- *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 = debug_xalloc (dhandle, 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);
if (tagname != NULL)
strcat (physname, tagname);
*pphysname = physname;
}
- if (*argtypes == '\0')
+ if (*argtypes == '\0' || is_destructor)
{
- args = (debug_type *) xmalloc (sizeof *args);
+ args = debug_xalloc (dhandle, sizeof (*args));
*args = NULL;
return debug_make_method_type (dhandle, return_type, class_type, args,
false);
}
- args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs);
+ args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs, physname_len);
if (args == NULL)
return DEBUG_TYPE_NULL;
This function is called when we have parsed all the method declarations,
so we can look for the vptr base class info. */
-static boolean
-parse_stab_tilde_field (dhandle, info, pp, typenums, retvptrbase, retownvptr)
- PTR dhandle;
- struct stab_handle *info;
- const char **pp;
- const int *typenums;
- debug_type *retvptrbase;
- boolean *retownvptr;
+static bool
+parse_stab_tilde_field (void *dhandle,
+ struct stab_handle *info,
+ const char **pp,
+ const int *typenums,
+ debug_type *retvptrbase,
+ bool *retownvptr,
+ const char *p_end)
{
const char *orig;
const char *hold;
*retownvptr = false;
orig = *pp;
-
- /* If we are positioned at a ';', then skip it. */
+ 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 == '-')
{
/* Obsolete flags that used to indicate the presence of
- constructors and/or destructors. */
+ constructors and/or destructors. */
++*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 != ';')
*pp = p + 1;
}
- return true;
+ return true;
}
/* Read a definition of an array type. */
static debug_type
-parse_stab_array_type (dhandle, info, pp, stringp)
- PTR dhandle;
- struct stab_handle *info;
- const char **pp;
- boolean stringp;
+parse_stab_array_type (void *dhandle,
+ struct stab_handle *info,
+ const char **pp,
+ bool stringp,
+ const char *p_end)
{
const char *orig;
const char *p;
int typenums[2];
debug_type index_type;
- boolean adjustable;
+ bool adjustable;
bfd_signed_vma lower, upper;
debug_type element_type;
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))
- return false;
+ 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");
{
index_type = debug_make_int_type (dhandle, 4, false);
if (index_type == DEBUG_TYPE_NULL)
- return false;
+ return DEBUG_TYPE_NULL;
}
*pp = p;
}
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 ((unsigned char) **pp) && **pp != '-')
+ if (! ISDIGIT (**pp) && **pp != '-' && **pp != 0)
{
++*pp;
adjustable = true;
}
- lower = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
+ lower = (bfd_signed_vma) parse_number (pp, (bool *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
- return false;
+ return DEBUG_TYPE_NULL;
}
++*pp;
- if (! isdigit ((unsigned char) **pp) && **pp != '-')
+ if (! ISDIGIT (**pp) && **pp != '-' && **pp != 0)
{
++*pp;
adjustable = true;
}
- upper = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
+ upper = (bfd_signed_vma) parse_number (pp, (bool *) NULL, p_end);
if (**pp != ';')
{
bad_stab (orig);
- return false;
+ return DEBUG_TYPE_NULL;
}
++*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 false;
+ return DEBUG_TYPE_NULL;
if (adjustable)
{
upper, stringp);
}
-/* Keep a stack of N_BINCL include files. */
+/* This struct holds information about files we have seen using
+ N_BINCL. */
struct bincl_file
{
+ /* The next N_BINCL file. */
struct bincl_file *next;
+ /* The next N_BINCL on the stack. */
+ struct bincl_file *next_stack;
+ /* The file name. */
const char *name;
+ /* The hash value. */
+ bfd_vma hash;
+ /* The file index. */
+ unsigned int file;
+ /* The list of types defined in this file. */
+ struct stab_types *file_types;
};
/* Start a new N_BINCL file, pushing it onto the stack. */
static void
-push_bincl (info, name)
- struct stab_handle *info;
- const char *name;
+push_bincl (void *dhandle, 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_stack;
+ n = debug_xalloc (dhandle, 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 ((PTR) info->file_types,
- (info->files
- * sizeof *info->file_types)));
- info->file_types[info->files - 1] = NULL;
+ info->file_types = xrealloc (info->file_types,
+ info->files * sizeof (*info->file_types));
+ info->file_types[n->file] = NULL;
}
/* Finish an N_BINCL file, at an N_EINCL, popping the name off the
stack. */
static const char *
-pop_bincl (info)
- struct stab_handle *info;
+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;
- free (o);
+ 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)
return info->main_filename;
return info->bincl_stack->name;
}
+/* Handle an N_EXCL: get the types from the corresponding N_BINCL. */
+
+static bool
+find_excl (struct stab_handle *info, const char *name, bfd_vma hash)
+{
+ struct bincl_file *l;
+
+ ++info->files;
+ info->file_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;
+}
+
/* Handle a variable definition. gcc emits variable definitions for a
block before the N_LBRAC, so we must hold onto them until we see
it. The SunPRO compiler emits variable definitions after the
N_LBRAC, so we can call debug_record_variable immediately. */
-static boolean
-stab_record_variable (dhandle, info, name, type, kind, val)
- PTR dhandle;
- struct stab_handle *info;
- const char *name;
- debug_type type;
- enum debug_var_kind kind;
- bfd_vma val;
+static bool
+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;
|| (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 = debug_xzalloc (dhandle, sizeof (*v));
v->next = info->pending;
v->name = name;
/* Emit pending variable definitions. This is called after we see the
N_LBRAC that starts the block. */
-static boolean
-stab_emit_pending_vars (dhandle, info)
- PTR dhandle;
- struct stab_handle *info;
+static bool
+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;
+ v = v->next;
}
info->pending = NULL;
/* Find the slot for a type in the database. */
static debug_type *
-stab_find_slot (info, typenums)
- struct stab_handle *info;
- const int *typenums;
+stab_find_slot (void *dhandle, struct stab_handle *info, const int *typenums)
{
- int filenum;
- int index;
+ unsigned int filenum;
+ unsigned int tindex;
+ unsigned int base_index;
struct stab_types **ps;
filenum = typenums[0];
- index = typenums[1];
+ tindex = typenums[1];
- if (filenum < 0 || (unsigned int) filenum >= info->files)
+ if (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);
+ fprintf (stderr, _("Type file number %d out of range\n"), filenum);
return NULL;
}
ps = info->file_types + filenum;
+ base_index = tindex / STAB_TYPES_SLOTS * STAB_TYPES_SLOTS;
+ tindex -= base_index;
+ while (*ps && (*ps)->base_index < base_index)
+ ps = &(*ps)->next;
- while (index >= STAB_TYPES_SLOTS)
+ if (*ps == NULL || (*ps)->base_index != base_index)
{
- 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);
+ struct stab_types *n = debug_xzalloc (dhandle, sizeof (*n));
+ n->next = *ps;
+ n->base_index = base_index;
+ *ps = n;
}
- return (*ps)->types + index;
+ return (*ps)->types + tindex;
}
/* Find a type given a type number. If the type has not been
allocated yet, create an indirect type. */
static debug_type
-stab_find_type (dhandle, info, typenums)
- PTR dhandle;
- struct stab_handle *info;
- const int *typenums;
+stab_find_type (void *dhandle, struct stab_handle *info, const int *typenums)
{
debug_type *slot;
return stab_xcoff_builtin_type (dhandle, info, typenums[1]);
}
- slot = stab_find_slot (info, typenums);
+ slot = stab_find_slot (dhandle, info, typenums);
if (slot == NULL)
return DEBUG_TYPE_NULL;
/* Record that a given type number refers to a given type. */
-static boolean
-stab_record_type (dhandle, info, typenums, type)
- PTR dhandle;
- struct stab_handle *info;
- const int *typenums;
- debug_type type;
+static bool
+stab_record_type (void *dhandle, struct stab_handle *info,
+ const int *typenums, debug_type type)
{
debug_type *slot;
- slot = stab_find_slot (info, typenums);
+ slot = stab_find_slot (dhandle, info, typenums);
if (slot == NULL)
return false;
/* Return an XCOFF builtin type. */
static debug_type
-stab_xcoff_builtin_type (dhandle, info, typenum)
- PTR dhandle;
- struct stab_handle *info;
- int typenum;
+stab_xcoff_builtin_type (void *dhandle, struct stab_handle *info,
+ unsigned int typenum)
{
debug_type rettype;
const char *name;
- if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT)
+ typenum = -typenum - 1;
+ if (typenum >= XCOFF_TYPE_COUNT)
{
- fprintf (stderr, "Unrecognized XCOFF type %d\n", typenum);
+ fprintf (stderr, _("Unrecognized XCOFF type %d\n"), -typenum - 1);
return DEBUG_TYPE_NULL;
}
- if (info->xcoff_types[-typenum] != NULL)
- return info->xcoff_types[-typenum];
+ if (info->xcoff_types[typenum] != NULL)
+ return info->xcoff_types[typenum];
- switch (-typenum)
+ switch (typenum)
{
- case 1:
+ case 0:
/* The size of this and all the other types are fixed, defined
by the debugging format. */
name = "int";
rettype = debug_make_int_type (dhandle, 4, false);
break;
- case 2:
+ case 1:
name = "char";
rettype = debug_make_int_type (dhandle, 1, false);
break;
- case 3:
+ case 2:
name = "short";
rettype = debug_make_int_type (dhandle, 2, false);
break;
- case 4:
+ case 3:
name = "long";
rettype = debug_make_int_type (dhandle, 4, false);
break;
- case 5:
+ case 4:
name = "unsigned char";
rettype = debug_make_int_type (dhandle, 1, true);
break;
- case 6:
+ case 5:
name = "signed char";
rettype = debug_make_int_type (dhandle, 1, false);
break;
- case 7:
+ case 6:
name = "unsigned short";
rettype = debug_make_int_type (dhandle, 2, true);
break;
- case 8:
+ case 7:
name = "unsigned int";
rettype = debug_make_int_type (dhandle, 4, true);
break;
- case 9:
+ case 8:
name = "unsigned";
rettype = debug_make_int_type (dhandle, 4, true);
- case 10:
+ break;
+ case 9:
name = "unsigned long";
rettype = debug_make_int_type (dhandle, 4, true);
break;
- case 11:
+ case 10:
name = "void";
rettype = debug_make_void_type (dhandle);
break;
- case 12:
+ case 11:
/* IEEE single precision (32 bit). */
name = "float";
rettype = debug_make_float_type (dhandle, 4);
break;
- case 13:
+ case 12:
/* IEEE double precision (64 bit). */
name = "double";
rettype = debug_make_float_type (dhandle, 8);
break;
- case 14:
+ case 13:
/* This is an IEEE double on the RS/6000, and different machines
with different sizes for "long double" should use different
negative type numbers. See stabs.texinfo. */
name = "long double";
rettype = debug_make_float_type (dhandle, 8);
break;
- case 15:
+ case 14:
name = "integer";
rettype = debug_make_int_type (dhandle, 4, false);
break;
- case 16:
+ case 15:
name = "boolean";
rettype = debug_make_bool_type (dhandle, 4);
break;
- case 17:
+ case 16:
name = "short real";
rettype = debug_make_float_type (dhandle, 4);
break;
- case 18:
+ case 17:
name = "real";
rettype = debug_make_float_type (dhandle, 8);
break;
- case 19:
+ case 18:
/* FIXME */
name = "stringptr";
rettype = NULL;
break;
- case 20:
+ case 19:
/* FIXME */
name = "character";
rettype = debug_make_int_type (dhandle, 1, true);
break;
- case 21:
+ case 20:
name = "logical*1";
rettype = debug_make_bool_type (dhandle, 1);
break;
- case 22:
+ case 21:
name = "logical*2";
rettype = debug_make_bool_type (dhandle, 2);
break;
- case 23:
+ case 22:
name = "logical*4";
rettype = debug_make_bool_type (dhandle, 4);
break;
- case 24:
+ case 23:
name = "logical";
rettype = debug_make_bool_type (dhandle, 4);
break;
- case 25:
+ case 24:
/* Complex type consisting of two IEEE single precision values. */
name = "complex";
rettype = debug_make_complex_type (dhandle, 8);
break;
- case 26:
+ case 25:
/* Complex type consisting of two IEEE double precision values. */
name = "double complex";
rettype = debug_make_complex_type (dhandle, 16);
break;
- case 27:
+ case 26:
name = "integer*1";
rettype = debug_make_int_type (dhandle, 1, false);
break;
- case 28:
+ case 27:
name = "integer*2";
rettype = debug_make_int_type (dhandle, 2, false);
break;
- case 29:
+ case 28:
name = "integer*4";
rettype = debug_make_int_type (dhandle, 4, false);
break;
- case 30:
+ case 29:
/* FIXME */
name = "wchar";
rettype = debug_make_int_type (dhandle, 2, false);
break;
- case 31:
+ case 30:
name = "long long";
rettype = debug_make_int_type (dhandle, 8, false);
break;
- case 32:
+ case 31:
name = "unsigned long long";
rettype = debug_make_int_type (dhandle, 8, true);
break;
- case 33:
+ case 32:
name = "logical*8";
rettype = debug_make_bool_type (dhandle, 8);
break;
- case 34:
+ case 33:
name = "integer*8";
rettype = debug_make_int_type (dhandle, 8, false);
break;
}
rettype = debug_name_type (dhandle, name, rettype);
-
- info->xcoff_types[-typenum] = rettype;
-
+ info->xcoff_types[typenum] = rettype;
return rettype;
}
/* Find or create a tagged type. */
static debug_type
-stab_find_tagged_type (dhandle, info, p, len, kind)
- PTR dhandle;
- struct stab_handle *info;
- const char *p;
- int len;
- enum debug_type_kind kind;
+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);
+ name = savestring (dhandle, p, len);
/* We pass DEBUG_KIND_ILLEGAL because we want all tags in the same
namespace. This is right for C, and I don't know how to handle
other languages. FIXME. */
dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL);
if (dtype != DEBUG_TYPE_NULL)
- {
- free (name);
- return dtype;
- }
+ return dtype;
/* We need to allocate an entry on the undefined tag list. */
for (st = info->tags; st != NULL; st = st->next)
{
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 = debug_xzalloc (dhandle, sizeof (*st));
st->next = info->tags;
st->name = name;
struct stab_demangle_info
{
/* The debugging information handle. */
- PTR dhandle;
+ void *dhandle;
/* The stab information handle. */
struct stab_handle *info;
/* The array of arguments we are building. */
debug_type *args;
/* Whether the method takes a variable number of arguments. */
- boolean varargs;
+ bool varargs;
/* The array of types we have remembered. */
struct stab_demangle_typestring *typestrings;
/* The number of typestrings. */
unsigned int typestring_alloc;
};
-static void stab_bad_demangle PARAMS ((const char *));
-static unsigned int stab_demangle_count PARAMS ((const char **));
-static boolean stab_demangle_get_count
- PARAMS ((const char **, unsigned int *));
-static boolean stab_demangle_prefix
- PARAMS ((struct stab_demangle_info *, const char **));
-static boolean stab_demangle_function_name
- PARAMS ((struct stab_demangle_info *, const char **, const char *));
-static boolean stab_demangle_signature
- PARAMS ((struct stab_demangle_info *, const char **));
-static boolean stab_demangle_qualified
- PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
-static boolean stab_demangle_template
- PARAMS ((struct stab_demangle_info *, const char **));
-static boolean stab_demangle_class
- PARAMS ((struct stab_demangle_info *, const char **, const char **));
-static boolean stab_demangle_args
- PARAMS ((struct stab_demangle_info *, const char **, debug_type **,
- boolean *));
-static boolean stab_demangle_arg
- PARAMS ((struct stab_demangle_info *, const char **, debug_type **,
- unsigned int *, unsigned int *));
-static boolean stab_demangle_type
- PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
-static boolean stab_demangle_fund_type
- PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
-static boolean stab_demangle_remember_type
- PARAMS ((struct stab_demangle_info *, const char *, int));
+static void stab_bad_demangle (const char *);
+static unsigned int stab_demangle_count (const char **);
+static bool stab_demangle_get_count (const char **, unsigned int *);
+static bool stab_demangle_prefix
+ (struct stab_demangle_info *, const char **, unsigned int);
+static bool stab_demangle_function_name
+ (struct stab_demangle_info *, const char **, const char *);
+static bool stab_demangle_signature
+ (struct stab_demangle_info *, const char **);
+static bool stab_demangle_qualified
+ (struct stab_demangle_info *, const char **, debug_type *);
+static bool stab_demangle_template
+ (struct stab_demangle_info *, const char **, char **);
+static bool stab_demangle_class
+ (struct stab_demangle_info *, const char **, const char **);
+static bool stab_demangle_args
+ (struct stab_demangle_info *, const char **, debug_type **, bool *);
+static bool stab_demangle_arg
+ (struct stab_demangle_info *, const char **, debug_type **,
+ unsigned int *, unsigned int *);
+static bool stab_demangle_type
+ (struct stab_demangle_info *, const char **, debug_type *);
+static bool stab_demangle_fund_type
+ (struct stab_demangle_info *, const char **, debug_type *);
+static bool stab_demangle_remember_type
+ (struct stab_demangle_info *, const char *, int);
/* Warn about a bad demangling. */
static void
-stab_bad_demangle (s)
- const char *s;
+stab_bad_demangle (const char *s)
{
- fprintf (stderr, "bad mangled name `%s'\n", s);
+ fprintf (stderr, _("bad mangled name `%s'\n"), s);
}
/* Get a count from a stab string. */
static unsigned int
-stab_demangle_count (pp)
- const char **pp;
+stab_demangle_count (const char **pp)
{
unsigned int count;
count = 0;
- while (isdigit ((unsigned char) **pp))
+ while (ISDIGIT (**pp))
{
count *= 10;
count += **pp - '0';
/* Require a count in a string. The count may be multiple digits, in
which case it must end in an underscore. */
-static boolean
-stab_demangle_get_count (pp, pi)
- const char **pp;
- unsigned int *pi;
+static bool
+stab_demangle_get_count (const char **pp, unsigned int *pi)
{
- if (! isdigit ((unsigned char) **pp))
+ if (! ISDIGIT (**pp))
return false;
*pi = **pp - '0';
++*pp;
- if (isdigit ((unsigned char) **pp))
+ if (ISDIGIT (**pp))
{
unsigned int count;
const char *p;
count += *p - '0';
++p;
}
- while (isdigit ((unsigned char) *p));
+ while (ISDIGIT (*p));
if (*p == '_')
{
*pp = p + 1;
terminated array of argument types. */
static debug_type *
-stab_demangle_argtypes (dhandle, info, physname, pvarargs)
- PTR dhandle;
- struct stab_handle *info;
- const char *physname;
- boolean *pvarargs;
+stab_demangle_argtypes (void *dhandle, struct stab_handle *info,
+ const char *physname, bool *pvarargs,
+ unsigned int physname_len)
{
struct stab_demangle_info minfo;
+ /* Check for the g++ V3 ABI. */
+ 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.typestrings
+ = xmalloc (minfo.typestring_alloc * sizeof (*minfo.typestrings));
minfo.typestring_count = 0;
/* cplus_demangle checks for special GNU mangled forms, but we can't
see any of them in mangled method argument types. */
- if (! stab_demangle_prefix (&minfo, &physname))
+ if (! stab_demangle_prefix (&minfo, &physname, physname_len))
goto error_return;
if (*physname != '\0')
}
free (minfo.typestrings);
- minfo.typestrings = NULL;
if (minfo.args == NULL)
- fprintf (stderr, "no argument types in mangled string\n");
+ fprintf (stderr, _("no argument types in mangled string\n"));
*pvarargs = minfo.varargs;
return minfo.args;
error_return:
- if (minfo.typestrings != NULL)
- free (minfo.typestrings);
+ free (minfo.typestrings);
return NULL;
}
/* Demangle the prefix of the mangled name. */
-static boolean
-stab_demangle_prefix (minfo, pp)
- struct stab_demangle_info *minfo;
- const char **pp;
+static bool
+stab_demangle_prefix (struct stab_demangle_info *minfo, const char **pp,
+ unsigned int physname_len)
{
const char *scan;
unsigned int i;
/* cplus_demangle checks for global constructors and destructors,
but we can't see them in mangled argument types. */
- /* Look for `__'. */
- scan = *pp;
- do
+ if (physname_len)
+ scan = *pp + physname_len;
+ else
{
- scan = strchr (scan, '_');
- }
- while (scan != NULL && *++scan != '_');
+ /* Look for `__'. */
+ scan = *pp;
+ do
+ scan = strchr (scan, '_');
+ while (scan != NULL && *++scan != '_');
- if (scan == NULL)
- {
- stab_bad_demangle (*pp);
- return false;
- }
+ if (scan == NULL)
+ {
+ stab_bad_demangle (*pp);
+ return false;
+ }
- --scan;
+ --scan;
- /* We found `__'; move ahead to the last contiguous `__' pair. */
- i = strspn (scan, "_");
- if (i > 2)
- scan += i - 2;
+ /* We found `__'; move ahead to the last contiguous `__' pair. */
+ i = strspn (scan, "_");
+ if (i > 2)
+ scan += i - 2;
+ }
if (scan == *pp
- && (isdigit ((unsigned char) scan[2])
+ && (ISDIGIT (scan[2])
|| scan[2] == 'Q'
|| scan[2] == 't'))
{
return true;
}
else if (scan == *pp
- && ! isdigit ((unsigned char) scan[2])
+ && ! ISDIGIT (scan[2])
&& scan[2] != 't')
{
/* Look for the `__' that separates the prefix from the
double underscore which separates the function name from the
signature. */
-static boolean
-stab_demangle_function_name (minfo, pp, scan)
- struct stab_demangle_info *minfo;
- const char **pp;
- const char *scan;
+static bool
+stab_demangle_function_name (struct stab_demangle_info *minfo,
+ const char **pp, const char *scan)
{
const char *name;
*pp = scan + 2;
if (*pp - name >= 5
- && strncmp (name, "type", 4) == 0
+ && startswith (name, "type")
&& (name[4] == '$' || name[4] == '.'))
{
const char *tem;
/* Demangle the signature. This is where the argument types are
found. */
-static boolean
-stab_demangle_signature (minfo, pp)
- struct stab_demangle_info *minfo;
- const char **pp;
+static bool
+stab_demangle_signature (struct stab_demangle_info *minfo, const char **pp)
{
const char *orig;
- boolean expect_func, func_done;
+ bool expect_func, func_done;
const char *hold;
orig = *pp;
/* Template. */
if (hold == NULL)
hold = *pp;
- if (! stab_demangle_template (minfo, pp)
+ if (! stab_demangle_template (minfo, pp, (char **) NULL)
|| ! stab_demangle_remember_type (minfo, hold, *pp - hold))
return false;
hold = NULL;
/* Demangle a qualified name, such as "Q25Outer5Inner" which is the
mangled form of "Outer::Inner". */
-static boolean
-stab_demangle_qualified (minfo, pp, ptype)
- struct stab_demangle_info *minfo;
- const char **pp;
- debug_type *ptype;
+static bool
+stab_demangle_qualified (struct stab_demangle_info *minfo, const char **pp,
+ debug_type *ptype)
{
const char *orig;
const char *p;
preceded by an underscore (to distinguish it from the <= 9
case) and followed by an underscore. */
p = *pp + 2;
- if (! isdigit ((unsigned char) *p) || *p == '0')
+ if (! ISDIGIT (*p) || *p == '0')
{
stab_bad_demangle (orig);
return false;
}
qualifiers = atoi (p);
- while (isdigit ((unsigned char) *p))
+ while (ISDIGIT (*p))
++p;
if (*p != '_')
{
++*pp;
if (**pp == 't')
{
- /* FIXME: I don't know how to handle the ptype != NULL case
- here. */
- if (! stab_demangle_template (minfo, pp))
+ 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);
+ if (context == DEBUG_TYPE_NULL)
+ return false;
+ }
}
else
{
not give us enough information to figure out the
latter case. */
- name = savestring (*pp, len);
+ name = savestring (minfo->dhandle, *pp, len);
for (; *fields != DEBUG_FIELD_NULL; fields++)
{
break;
}
}
-
- free (name);
}
if (context == DEBUG_TYPE_NULL)
{
- /* We have to fall back on finding the type by name.
+ /* We have to fall back on finding the type by name.
If there are more types to come, then this must
be a class. Otherwise, it could be anything. */
{
char *name;
- name = savestring (*pp, len);
+ name = savestring (minfo->dhandle, *pp, len);
context = debug_find_named_type (minfo->dhandle,
name);
- free (name);
}
if (context == DEBUG_TYPE_NULL)
return true;
}
-/* Demangle a template. */
+/* Demangle a template. If PNAME is not NULL, this sets *PNAME to a
+ string representation of the template. */
-static boolean
-stab_demangle_template (minfo, pp)
- struct stab_demangle_info *minfo;
- const char **pp;
+static bool
+stab_demangle_template (struct stab_demangle_info *minfo, const char **pp,
+ char **pname)
{
const char *orig;
unsigned int r, i;
else
{
const char *old_p;
- boolean pointerp, realp, integralp, charp, boolp;
- boolean done;
+ bool pointerp, realp, integralp, charp, boolp;
+ bool done;
old_p = *pp;
pointerp = false;
{
if (**pp == 'm')
++*pp;
- while (isdigit ((unsigned char) **pp))
+ while (ISDIGIT (**pp))
++*pp;
}
else if (charp)
{
if (**pp == 'm')
++*pp;
- while (isdigit ((unsigned char) **pp))
+ while (ISDIGIT (**pp))
++*pp;
if (**pp == '.')
{
++*pp;
- while (isdigit ((unsigned char) **pp))
+ while (ISDIGIT (**pp))
++*pp;
}
if (**pp == 'e')
{
++*pp;
- while (isdigit ((unsigned char) **pp))
+ while (ISDIGIT (**pp))
++*pp;
}
}
{
unsigned int len;
- if (! stab_demangle_get_count (pp, &len))
+ len = stab_demangle_count (pp);
+ if (len == 0)
{
stab_bad_demangle (orig);
return false;
}
}
+ /* We can translate this to a string fairly easily by invoking the
+ regular demangling routine. */
+ if (pname != NULL)
+ {
+ char *s1, *s2, *s3, *s4 = NULL;
+ char *from, *to;
+
+ s1 = savestring (minfo->dhandle, orig, *pp - orig);
+
+ s2 = concat ("NoSuchStrinG__", s1, (const char *) NULL);
+
+ s3 = cplus_demangle (s2, demangle_flags);
+
+ free (s2);
+
+ if (s3 != NULL)
+ s4 = strstr (s3, "::NoSuchStrinG");
+ if (s3 == NULL || s4 == NULL)
+ {
+ stab_bad_demangle (orig);
+ free (s3);
+ return false;
+ }
+
+ /* Eliminating all spaces, except those between > characters,
+ makes it more likely that the demangled name will match the
+ name which g++ used as the structure name. */
+ for (from = to = s3; from != s4; ++from)
+ if (*from != ' '
+ || (from[1] == '>' && from > s3 && from[-1] == '>'))
+ *to++ = *from;
+
+ *pname = savestring (minfo->dhandle, s3, to - s3);
+
+ free (s3);
+ }
+
return true;
}
/* Demangle a class name. */
-static boolean
-stab_demangle_class (minfo, pp, pstart)
- struct stab_demangle_info *minfo;
- const char **pp;
- const char **pstart;
+static bool
+stab_demangle_class (struct stab_demangle_info *minfo ATTRIBUTE_UNUSED,
+ const char **pp, const char **pstart)
{
const char *orig;
unsigned int n;
/* Demangle function arguments. If the pargs argument is not NULL, it
is set to a NULL terminated array holding the arguments. */
-static boolean
-stab_demangle_args (minfo, pp, pargs, pvarargs)
- struct stab_demangle_info *minfo;
- const char **pp;
- debug_type **pargs;
- boolean *pvarargs;
+static bool
+stab_demangle_args (struct stab_demangle_info *minfo, const char **pp,
+ debug_type **pargs, bool *pvarargs)
{
const char *orig;
unsigned int alloc, count;
alloc = 10;
if (pargs != NULL)
- {
- *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs);
- *pvarargs = false;
- }
+ *pargs = xmalloc (alloc * sizeof (**pargs));
+ if (pvarargs != NULL)
+ *pvarargs = false;
count = 0;
while (**pp != '_' && **pp != '\0' && **pp != 'e')
else
{
if (! stab_demangle_get_count (pp, &r))
- {
- stab_bad_demangle (orig);
- return false;
- }
+ goto bad;
}
- if (! stab_demangle_get_count (pp, &t))
- {
- stab_bad_demangle (orig);
- return false;
- }
+ if (!stab_demangle_get_count (pp, &t)
+ || t >= minfo->typestring_count)
+ goto bad;
- 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;
+ goto fail;
}
}
else
{
if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc))
- return false;
+ goto fail;
}
}
if (pargs != NULL)
- (*pargs)[count] = DEBUG_TYPE_NULL;
+ {
+ debug_type *xargs;
+ (*pargs)[count] = DEBUG_TYPE_NULL;
+ xargs = debug_xalloc (minfo->dhandle, (count + 1) * sizeof (*xargs));
+ memcpy (xargs, *pargs, (count + 1) * sizeof (*xargs));
+ free (*pargs);
+ *pargs = xargs;
+ }
if (**pp == 'e')
{
- if (pargs != NULL)
+ if (pvarargs != NULL)
*pvarargs = true;
++*pp;
}
-
return true;
+
+ bad:
+ stab_bad_demangle (orig);
+ fail:
+ if (pargs != NULL)
+ {
+ free (*pargs);
+ *pargs = NULL;
+ }
+ return false;
}
/* Demangle a single argument. */
-static boolean
-stab_demangle_arg (minfo, pp, pargs, pcount, palloc)
- struct stab_demangle_info *minfo;
- const char **pp;
- debug_type **pargs;
- unsigned int *pcount;
- unsigned int *palloc;
+static bool
+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;
if (*pcount + 1 >= *palloc)
{
*palloc += 10;
- *pargs = ((debug_type *)
- xrealloc (*pargs, *palloc * sizeof **pargs));
+ *pargs = xrealloc (*pargs, *palloc * sizeof (**pargs));
}
(*pargs)[*pcount] = type;
++*pcount;
/* Demangle a type. If the ptype argument is not NULL, *ptype is set
to the newly allocated type. */
-static boolean
-stab_demangle_type (minfo, pp, ptype)
- struct stab_demangle_info *minfo;
- const char **pp;
- debug_type *ptype;
+static bool
+stab_demangle_type (struct stab_demangle_info *minfo, const char **pp,
+ debug_type *ptype)
{
const char *orig;
high = 0;
while (**pp != '\0' && **pp != '_')
{
- if (! isdigit ((unsigned char) **pp))
+ if (! ISDIGIT (**pp))
{
stab_bad_demangle (orig);
return false;
/* A function. */
{
debug_type *args;
- boolean varargs;
+ bool varargs;
++*pp;
if (! stab_demangle_args (minfo, pp,
? (debug_type **) NULL
: &args),
(ptype == NULL
- ? (boolean *) NULL
+ ? (bool *) NULL
: &varargs)))
return false;
if (**pp != '_')
case 'M':
case 'O':
{
- boolean memberp, constp, volatilep;
+ bool memberp;
+ debug_type class_type = DEBUG_TYPE_NULL;
debug_type *args;
- boolean varargs;
+ bool varargs;
unsigned int n;
const char *name;
memberp = **pp == 'M';
- constp = false;
- volatilep = false;
args = NULL;
varargs = false;
++*pp;
- if (! isdigit ((unsigned char) **pp))
+ if (ISDIGIT (**pp))
{
- stab_bad_demangle (orig);
- return false;
+ 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;
+ }
}
- n = stab_demangle_count (pp);
- if (strlen (*pp) < n)
+ 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;
}
- name = *pp;
- *pp += n;
if (memberp)
{
if (**pp == 'C')
{
- constp = true;
++*pp;
}
else if (**pp == 'V')
{
- volatilep = true;
++*pp;
}
if (**pp != 'F')
? (debug_type **) NULL
: &args),
(ptype == NULL
- ? (boolean *) NULL
+ ? (bool *) NULL
: &varargs)))
return false;
}
if (ptype != NULL)
{
- debug_type class_type;
-
- class_type = stab_find_tagged_type (minfo->dhandle, minfo->info,
- name, (int) n,
- DEBUG_KIND_CLASS);
- if (class_type == DEBUG_TYPE_NULL)
- return false;
-
if (! memberp)
*ptype = debug_make_offset_type (minfo->dhandle, class_type,
*ptype);
case 'Q':
{
- const char *hold;
-
- hold = *pp;
if (! stab_demangle_qualified (minfo, pp, ptype))
return false;
}
/* Demangle a fundamental type. If the ptype argument is not NULL,
*ptype is set to the newly allocated type. */
-static boolean
-stab_demangle_fund_type (minfo, pp, ptype)
- struct stab_demangle_info *minfo;
- const char **pp;
- debug_type *ptype;
+static bool
+stab_demangle_fund_type (struct stab_demangle_info *minfo, const char **pp,
+ debug_type *ptype)
{
const char *orig;
- boolean constp, volatilep, unsignedp, signedp;
- boolean done;
+ bool constp, volatilep, unsignedp, signedp;
+ bool done;
orig = *pp;
case 'G':
++*pp;
- if (! isdigit ((unsigned char) **pp))
+ if (! ISDIGIT (**pp))
{
stab_bad_demangle (orig);
return false;
{
char *name;
- name = savestring (hold, *pp - hold);
+ name = savestring (minfo->dhandle, hold, *pp - hold);
*ptype = debug_find_named_type (minfo->dhandle, 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;
}
- free (name);
}
}
break;
case 't':
- if (! stab_demangle_template (minfo, pp))
- return false;
- if (ptype != NULL)
- {
- debug_type t;
-
- /* FIXME: I really don't know how a template should be
- represented in the current type system. Perhaps the
- template should be demangled into a string, and the type
- should be represented as a named type. However, I don't
- know what the base type of the named type should be. */
- t = debug_make_void_type (minfo->dhandle);
- t = debug_make_pointer_type (minfo->dhandle, t);
- t = debug_name_type (minfo->dhandle, "TEMPLATE", t);
- *ptype = 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);
+ if (*ptype == DEBUG_TYPE_NULL)
+ return false;
+ }
+ }
break;
default:
/* Remember a type string in a demangled string. */
-static boolean
-stab_demangle_remember_type (minfo, p, len)
- struct stab_demangle_info *minfo;
- const char *p;
- int len;
+static bool
+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
+ = xrealloc (minfo->typestrings,
+ minfo->typestring_alloc * sizeof (*minfo->typestrings));
}
minfo->typestrings[minfo->typestring_count].typestring = p;
return true;
}
+\f
+/* Demangle names encoded using the g++ V3 ABI. The newer versions of
+ g++ which use this ABI do not encode ordinary method argument types
+ in a mangled name; they simply output the argument types. However,
+ for a static method, g++ simply outputs the return type and the
+ physical name. So in that case we need to demangle the name here.
+ Here PHYSNAME is the physical name of the function, and we set the
+ variable pointed at by PVARARGS to indicate whether this function
+ is varargs. This returns NULL, or a NULL terminated array of
+ argument types. */
+
+static debug_type *
+stab_demangle_v3_argtypes (void *dhandle, struct stab_handle *info,
+ const char *physname, bool *pvarargs)
+{
+ struct demangle_component *dc;
+ void *mem;
+ debug_type *pargs;
+
+ dc = cplus_demangle_v3_components (physname, DMGL_PARAMS | demangle_flags, &mem);
+ if (dc == NULL)
+ {
+ stab_bad_demangle (physname);
+ return NULL;
+ }
+
+ /* We expect to see TYPED_NAME, and the right subtree describes the
+ function type. */
+ 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;
+}
+
+/* Demangle an argument list in a struct demangle_component tree.
+ Returns a DEBUG_TYPE_NULL terminated array of argument types, and
+ sets *PVARARGS to indicate whether this is a varargs function. */
+
+static debug_type *
+stab_demangle_v3_arglist (void *dhandle, struct stab_handle *info,
+ struct demangle_component *arglist,
+ bool *pvarargs)
+{
+ struct demangle_component *dc;
+ unsigned int alloc, count;
+ debug_type *pargs, *xargs;
+
+ alloc = 10;
+ pargs = xmalloc (alloc * sizeof (*pargs));
+ *pvarargs = false;
+
+ count = 0;
+
+ for (dc = arglist;
+ dc != NULL;
+ dc = dc->u.s_binary.right)
+ {
+ debug_type arg;
+ bool varargs;
+
+ if (dc->type != DEMANGLE_COMPONENT_ARGLIST)
+ {
+ fprintf (stderr, _("Unexpected type in v3 arglist demangling\n"));
+ free (pargs);
+ 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)
+ {
+ if (varargs)
+ {
+ *pvarargs = true;
+ continue;
+ }
+ free (pargs);
+ return NULL;
+ }
+
+ if (count + 1 >= alloc)
+ {
+ alloc += 10;
+ pargs = xrealloc (pargs, alloc * sizeof (*pargs));
+ }
+
+ pargs[count] = arg;
+ ++count;
+ }
+
+ pargs[count] = DEBUG_TYPE_NULL;
+ xargs = debug_xalloc (dhandle, (count + 1) * sizeof (*pargs));
+ memcpy (xargs, pargs, (count + 1) * sizeof (*pargs));
+ free (pargs);
+
+ return xargs;
+}
+
+/* Convert a struct demangle_component tree describing an argument
+ type into a debug_type. */
+
+static debug_type
+stab_demangle_v3_arg (void *dhandle, struct stab_handle *info,
+ struct demangle_component *dc, debug_type context,
+ bool *pvarargs)
+{
+ debug_type dt;
+
+ if (pvarargs != NULL)
+ *pvarargs = false;
+
+ switch (dc->type)
+ {
+ /* FIXME: These are demangle component types which we probably
+ need to handle one way or another. */
+ 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)
+ {
+ /* Try to find this type by looking through the context
+ class. */
+ 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;
+
+ /* 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 | demangle_flags, 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:
+ /* FIXME: We have no way to represent 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;
+ bool varargs;
+
+ if (dc->u.s_binary.left == NULL)
+ {
+ /* In this case the return type is actually unknown.
+ However, I'm not sure this will ever arise in practice;
+ normally an unknown return type would only appear at
+ the top level, which is handled above. */
+ 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;
+
+ /* 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 | demangle_flags, dc, 20, &alc);
+ if (p == NULL)
+ {
+ fprintf (stderr, _("Couldn't get demangled builtin type\n"));
+ return NULL;
+ }
+
+ /* The mangling is based on the type, but does not itself
+ indicate what the sizes are. So we have to guess. */
+ 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;
+ }
+ }
+}