+
+/* Find or create a tagged type. */
+
+static debug_type
+stab_find_tagged_type (void *dhandle, struct stab_handle *info,
+ const char *p, int len, enum debug_type_kind kind)
+{
+ char *name;
+ debug_type dtype;
+ struct stab_tag *st;
+
+ name = savestring (p, len);
+
+ /* 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;
+ }
+
+ /* We need to allocate an entry on the undefined tag list. */
+ for (st = info->tags; st != NULL; st = st->next)
+ {
+ if (st->name[0] == name[0]
+ && strcmp (st->name, name) == 0)
+ {
+ if (st->kind == DEBUG_KIND_ILLEGAL)
+ st->kind = kind;
+ free (name);
+ break;
+ }
+ }
+ if (st == NULL)
+ {
+ st = (struct stab_tag *) xmalloc (sizeof *st);
+ memset (st, 0, sizeof *st);
+
+ st->next = info->tags;
+ st->name = name;
+ st->kind = kind;
+ st->slot = DEBUG_TYPE_NULL;
+ st->type = debug_make_indirect_type (dhandle, &st->slot, name);
+ info->tags = st;
+ }
+
+ return st->type;
+}
+\f
+/* In order to get the correct argument types for a stubbed method, we
+ need to extract the argument types from a C++ mangled string.
+ Since the argument types can refer back to the return type, this
+ means that we must demangle the entire physical name. In gdb this
+ is done by calling cplus_demangle and running the results back
+ through the C++ expression parser. Since we have no expression
+ parser, we must duplicate much of the work of cplus_demangle here.
+
+ We assume that GNU style demangling is used, since this is only
+ done for method stubs, and only g++ should output that form of
+ debugging information. */
+
+/* This structure is used to hold a pointer to type information which
+ demangling a string. */
+
+struct stab_demangle_typestring
+{
+ /* The start of the type. This is not null terminated. */
+ const char *typestring;
+ /* The length of the type. */
+ unsigned int len;
+};
+
+/* This structure is used to hold information while demangling a
+ string. */
+
+struct stab_demangle_info
+{
+ /* The debugging information handle. */
+ 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. */
+ bfd_boolean varargs;
+ /* The array of types we have remembered. */
+ struct stab_demangle_typestring *typestrings;
+ /* The number of typestrings. */
+ unsigned int typestring_count;
+ /* The number of typestring slots we have allocated. */
+ unsigned int typestring_alloc;
+};
+
+static void stab_bad_demangle (const char *);
+static unsigned int stab_demangle_count (const char **);
+static bfd_boolean stab_demangle_get_count (const char **, unsigned int *);
+static bfd_boolean stab_demangle_prefix
+ (struct stab_demangle_info *, const char **, unsigned int);
+static bfd_boolean stab_demangle_function_name
+ (struct stab_demangle_info *, const char **, const char *);
+static bfd_boolean stab_demangle_signature
+ (struct stab_demangle_info *, const char **);
+static bfd_boolean stab_demangle_qualified
+ (struct stab_demangle_info *, const char **, debug_type *);
+static bfd_boolean stab_demangle_template
+ (struct stab_demangle_info *, const char **, char **);
+static bfd_boolean stab_demangle_class
+ (struct stab_demangle_info *, const char **, const char **);
+static bfd_boolean stab_demangle_args
+ (struct stab_demangle_info *, const char **, debug_type **, bfd_boolean *);
+static bfd_boolean stab_demangle_arg
+ (struct stab_demangle_info *, const char **, debug_type **,
+ unsigned int *, unsigned int *);
+static bfd_boolean stab_demangle_type
+ (struct stab_demangle_info *, const char **, debug_type *);
+static bfd_boolean stab_demangle_fund_type
+ (struct stab_demangle_info *, const char **, debug_type *);
+static bfd_boolean stab_demangle_remember_type
+ (struct stab_demangle_info *, const char *, int);
+
+/* Warn about a bad demangling. */
+
+static void
+stab_bad_demangle (const char *s)
+{
+ fprintf (stderr, _("bad mangled name `%s'\n"), s);
+}
+
+/* Get a count from a stab string. */
+
+static unsigned int
+stab_demangle_count (const char **pp)
+{
+ unsigned int count;
+
+ count = 0;
+ while (ISDIGIT (**pp))
+ {
+ count *= 10;
+ count += **pp - '0';
+ ++*pp;
+ }
+ return count;
+}
+
+/* Require a count in a string. The count may be multiple digits, in
+ which case it must end in an underscore. */
+
+static bfd_boolean
+stab_demangle_get_count (const char **pp, unsigned int *pi)
+{
+ if (! ISDIGIT (**pp))
+ return FALSE;
+
+ *pi = **pp - '0';
+ ++*pp;
+ if (ISDIGIT (**pp))
+ {
+ unsigned int count;
+ const char *p;
+
+ count = *pi;
+ p = *pp;
+ do
+ {
+ count *= 10;
+ count += *p - '0';
+ ++p;
+ }
+ while (ISDIGIT (*p));
+ if (*p == '_')
+ {
+ *pp = p + 1;
+ *pi = count;
+ }
+ }
+
+ return TRUE;
+}
+
+/* This function demangles a physical name, returning a NULL
+ terminated array of argument types. */
+
+static debug_type *
+stab_demangle_argtypes (void *dhandle, struct stab_handle *info,
+ const char *physname, bfd_boolean *pvarargs,
+ unsigned int physname_len)
+{
+ struct stab_demangle_info minfo;
+
+ /* 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.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, physname_len))
+ goto error_return;
+
+ if (*physname != '\0')
+ {
+ if (! stab_demangle_signature (&minfo, &physname))
+ goto error_return;
+ }
+
+ free (minfo.typestrings);
+ minfo.typestrings = NULL;
+
+ if (minfo.args == NULL)
+ fprintf (stderr, _("no argument types in mangled string\n"));
+
+ *pvarargs = minfo.varargs;
+ return minfo.args;
+
+ error_return:
+ if (minfo.typestrings != NULL)
+ free (minfo.typestrings);
+ return NULL;
+}
+
+/* Demangle the prefix of the mangled name. */
+
+static bfd_boolean
+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. */
+
+ if (physname_len)
+ scan = *pp + physname_len;
+ else
+ {
+ /* Look for `__'. */
+ scan = *pp;
+ do
+ scan = strchr (scan, '_');
+ while (scan != NULL && *++scan != '_');
+
+ if (scan == NULL)
+ {
+ stab_bad_demangle (*pp);
+ return FALSE;
+ }
+
+ --scan;
+
+ /* We found `__'; move ahead to the last contiguous `__' pair. */
+ i = strspn (scan, "_");
+ if (i > 2)
+ scan += i - 2;
+ }
+
+ if (scan == *pp
+ && (ISDIGIT (scan[2])
+ || scan[2] == 'Q'
+ || scan[2] == 't'))
+ {
+ /* This is a GNU style constructor name. */
+ *pp = scan + 2;
+ return TRUE;
+ }
+ else if (scan == *pp
+ && ! ISDIGIT (scan[2])
+ && scan[2] != 't')
+ {
+ /* Look for the `__' that separates the prefix from the
+ signature. */
+ while (*scan == '_')
+ ++scan;
+ scan = strstr (scan, "__");
+ if (scan == NULL || scan[2] == '\0')
+ {
+ stab_bad_demangle (*pp);
+ return FALSE;
+ }
+
+ return stab_demangle_function_name (minfo, pp, scan);
+ }
+ else if (scan[2] != '\0')
+ {
+ /* The name doesn't start with `__', but it does contain `__'. */
+ return stab_demangle_function_name (minfo, pp, scan);
+ }
+ else
+ {
+ stab_bad_demangle (*pp);
+ return FALSE;
+ }
+ /*NOTREACHED*/
+}
+
+/* Demangle a function name prefix. The scan argument points to the
+ double underscore which separates the function name from the
+ signature. */
+
+static bfd_boolean
+stab_demangle_function_name (struct stab_demangle_info *minfo,
+ const char **pp, const char *scan)
+{
+ const char *name;
+
+ /* The string from *pp to scan is the name of the function. We
+ don't care about the name, since we just looking for argument
+ types. However, for conversion operators, the name may include a
+ type which we must remember in order to handle backreferences. */
+
+ name = *pp;
+ *pp = scan + 2;
+
+ if (*pp - name >= 5
+ && CONST_STRNEQ (name, "type")
+ && (name[4] == '$' || name[4] == '.'))
+ {
+ const char *tem;
+
+ /* This is a type conversion operator. */
+ tem = name + 5;
+ if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
+ return FALSE;
+ }
+ else if (name[0] == '_'
+ && name[1] == '_'
+ && name[2] == 'o'
+ && name[3] == 'p')
+ {
+ const char *tem;
+
+ /* This is a type conversion operator. */
+ tem = name + 4;
+ if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Demangle the signature. This is where the argument types are
+ found. */
+
+static bfd_boolean
+stab_demangle_signature (struct stab_demangle_info *minfo, const char **pp)
+{
+ const char *orig;
+ bfd_boolean expect_func, func_done;
+ const char *hold;
+
+ orig = *pp;
+
+ expect_func = FALSE;
+ func_done = FALSE;
+ hold = NULL;
+
+ while (**pp != '\0')
+ {
+ switch (**pp)
+ {
+ case 'Q':
+ hold = *pp;
+ if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL)
+ || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
+ return FALSE;
+ expect_func = TRUE;
+ hold = NULL;
+ break;
+
+ case 'S':
+ /* Static member function. FIXME: Can this happen? */
+ if (hold == NULL)
+ hold = *pp;
+ ++*pp;
+ break;
+
+ case 'C':
+ /* Const member function. */
+ if (hold == NULL)
+ hold = *pp;
+ ++*pp;
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (hold == NULL)
+ hold = *pp;
+ if (! stab_demangle_class (minfo, pp, (const char **) NULL)
+ || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
+ return FALSE;
+ expect_func = TRUE;
+ hold = NULL;
+ break;
+
+ case 'F':
+ /* Function. I don't know if this actually happens with g++
+ output. */
+ hold = NULL;
+ func_done = TRUE;
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return FALSE;
+ break;
+
+ case 't':
+ /* Template. */
+ if (hold == NULL)
+ hold = *pp;
+ if (! stab_demangle_template (minfo, pp, (char **) NULL)
+ || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
+ return FALSE;
+ hold = NULL;
+ expect_func = TRUE;
+ break;
+
+ case '_':
+ /* At the outermost level, we cannot have a return type
+ specified, so if we run into another '_' at this point we
+ are dealing with a mangled name that is either bogus, or
+ has been mangled by some algorithm we don't know how to
+ deal with. So just reject the entire demangling. */
+ stab_bad_demangle (orig);
+ return FALSE;
+
+ default:
+ /* Assume we have stumbled onto the first outermost function
+ argument token, and start processing args. */
+ func_done = TRUE;
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return FALSE;
+ break;
+ }
+
+ if (expect_func)
+ {
+ func_done = TRUE;
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return FALSE;
+ }
+ }
+
+ if (! func_done)
+ {
+ /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
+ bar__3fooi is 'foo::bar(int)'. We get here when we find the
+ first case, and need to ensure that the '(void)' gets added
+ to the current declp. */
+ if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Demangle a qualified name, such as "Q25Outer5Inner" which is the
+ mangled form of "Outer::Inner". */
+
+static bfd_boolean
+stab_demangle_qualified (struct stab_demangle_info *minfo, const char **pp,
+ debug_type *ptype)
+{
+ const char *orig;
+ const char *p;
+ unsigned int qualifiers;
+ debug_type context;
+
+ orig = *pp;
+
+ switch ((*pp)[1])
+ {
+ case '_':
+ /* GNU mangled name with more than 9 classes. The count is
+ preceded by an underscore (to distinguish it from the <= 9
+ case) and followed by an underscore. */
+ p = *pp + 2;
+ if (! ISDIGIT (*p) || *p == '0')
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ qualifiers = atoi (p);
+ while (ISDIGIT (*p))
+ ++p;
+ if (*p != '_')
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ *pp = p + 1;
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ qualifiers = (*pp)[1] - '0';
+ /* Skip an optional underscore after the count. */
+ if ((*pp)[2] == '_')
+ ++*pp;
+ *pp += 2;
+ break;
+
+ case '0':
+ default:
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+
+ context = DEBUG_TYPE_NULL;
+
+ /* Pick off the names. */
+ while (qualifiers-- > 0)
+ {
+ if (**pp == '_')
+ ++*pp;
+ if (**pp == 't')
+ {
+ char *name;
+
+ if (! stab_demangle_template (minfo, pp,
+ ptype != NULL ? &name : NULL))
+ return FALSE;
+
+ if (ptype != NULL)
+ {
+ context = stab_find_tagged_type (minfo->dhandle, minfo->info,
+ name, strlen (name),
+ DEBUG_KIND_CLASS);
+ free (name);
+ if (context == DEBUG_TYPE_NULL)
+ return FALSE;
+ }
+ }
+ else
+ {
+ unsigned int len;
+
+ len = stab_demangle_count (pp);
+ if (strlen (*pp) < len)
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+
+ if (ptype != NULL)
+ {
+ const debug_field *fields;
+
+ fields = NULL;
+ if (context != DEBUG_TYPE_NULL)
+ fields = debug_get_fields (minfo->dhandle, context);
+
+ context = DEBUG_TYPE_NULL;
+
+ if (fields != NULL)
+ {
+ char *name;
+
+ /* Try to find the type by looking through the
+ fields of context until we find a field with the
+ same type. This ought to work for a class
+ defined within a class, but it won't work for,
+ e.g., an enum defined within a class. stabs does
+ not give us enough information to figure out the
+ latter case. */
+
+ name = savestring (*pp, len);
+
+ for (; *fields != DEBUG_FIELD_NULL; fields++)
+ {
+ debug_type ft;
+ const char *dn;
+
+ ft = debug_get_field_type (minfo->dhandle, *fields);
+ if (ft == NULL)
+ {
+ free (name);
+ return FALSE;
+ }
+ dn = debug_get_type_name (minfo->dhandle, ft);
+ if (dn != NULL && strcmp (dn, name) == 0)
+ {
+ context = ft;
+ break;
+ }
+ }
+
+ free (name);
+ }
+
+ if (context == DEBUG_TYPE_NULL)
+ {
+ /* 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. */
+
+ if (qualifiers == 0)
+ {
+ char *name;
+
+ name = savestring (*pp, len);
+ context = debug_find_named_type (minfo->dhandle,
+ name);
+ free (name);
+ }
+
+ if (context == DEBUG_TYPE_NULL)
+ {
+ context = stab_find_tagged_type (minfo->dhandle,
+ minfo->info,
+ *pp, len,
+ (qualifiers == 0
+ ? DEBUG_KIND_ILLEGAL
+ : DEBUG_KIND_CLASS));
+ if (context == DEBUG_TYPE_NULL)
+ return FALSE;
+ }
+ }
+ }
+
+ *pp += len;
+ }
+ }
+
+ if (ptype != NULL)
+ *ptype = context;
+
+ return TRUE;
+}
+
+/* Demangle a template. If PNAME is not NULL, this sets *PNAME to a
+ string representation of the template. */
+
+static bfd_boolean
+stab_demangle_template (struct stab_demangle_info *minfo, const char **pp,
+ char **pname)
+{
+ const char *orig;
+ unsigned int r, i;
+
+ orig = *pp;
+
+ ++*pp;
+
+ /* Skip the template name. */
+ r = stab_demangle_count (pp);
+ if (r == 0 || strlen (*pp) < r)
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ *pp += r;
+
+ /* Get the size of the parameter list. */
+ if (stab_demangle_get_count (pp, &r) == 0)
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+
+ for (i = 0; i < r; i++)
+ {
+ if (**pp == 'Z')
+ {
+ /* This is a type parameter. */
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
+ return FALSE;
+ }
+ else
+ {
+ const char *old_p;
+ bfd_boolean pointerp, realp, integralp, charp, boolp;
+ bfd_boolean done;
+
+ old_p = *pp;
+ pointerp = FALSE;
+ realp = FALSE;
+ integralp = FALSE;
+ charp = FALSE;
+ boolp = FALSE;
+ done = FALSE;
+
+ /* This is a value parameter. */
+
+ if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
+ return FALSE;
+
+ while (*old_p != '\0' && ! done)
+ {
+ switch (*old_p)
+ {
+ case 'P':
+ case 'p':
+ case 'R':
+ pointerp = TRUE;
+ done = TRUE;
+ break;
+ case 'C': /* Const. */
+ case 'S': /* Signed. */
+ case 'U': /* Unsigned. */
+ case 'V': /* Volatile. */
+ case 'F': /* Function. */
+ case 'M': /* Member function. */
+ case 'O': /* ??? */
+ ++old_p;
+ break;
+ case 'Q': /* Qualified name. */
+ integralp = TRUE;
+ done = TRUE;
+ break;
+ case 'T': /* Remembered type. */
+ abort ();
+ case 'v': /* Void. */
+ abort ();
+ case 'x': /* Long long. */
+ case 'l': /* Long. */
+ case 'i': /* Int. */
+ case 's': /* Short. */
+ case 'w': /* Wchar_t. */
+ integralp = TRUE;
+ done = TRUE;
+ break;
+ case 'b': /* Bool. */
+ boolp = TRUE;
+ done = TRUE;
+ break;
+ case 'c': /* Char. */
+ charp = TRUE;
+ done = TRUE;
+ break;
+ case 'r': /* Long double. */
+ case 'd': /* Double. */
+ case 'f': /* Float. */
+ realp = TRUE;
+ done = TRUE;
+ break;
+ default:
+ /* Assume it's a user defined integral type. */
+ integralp = TRUE;
+ done = TRUE;
+ break;
+ }
+ }
+
+ if (integralp)
+ {
+ if (**pp == 'm')
+ ++*pp;
+ while (ISDIGIT (**pp))
+ ++*pp;
+ }
+ else if (charp)
+ {
+ unsigned int val;
+
+ if (**pp == 'm')
+ ++*pp;
+ val = stab_demangle_count (pp);
+ if (val == 0)
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ }
+ else if (boolp)
+ {
+ unsigned int val;
+
+ val = stab_demangle_count (pp);
+ if (val != 0 && val != 1)
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ }
+ else if (realp)
+ {
+ if (**pp == 'm')
+ ++*pp;
+ while (ISDIGIT (**pp))
+ ++*pp;
+ if (**pp == '.')
+ {
+ ++*pp;
+ while (ISDIGIT (**pp))
+ ++*pp;
+ }
+ if (**pp == 'e')
+ {
+ ++*pp;
+ while (ISDIGIT (**pp))
+ ++*pp;
+ }
+ }
+ else if (pointerp)
+ {
+ unsigned int len;
+
+ len = stab_demangle_count (pp);
+ if (len == 0)
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ *pp += len;
+ }
+ }
+ }
+
+ /* 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 (orig, *pp - orig);
+
+ s2 = concat ("NoSuchStrinG__", s1, (const char *) NULL);
+
+ free (s1);
+
+ s3 = cplus_demangle (s2, demangle_flags);
+
+ free (s2);
+
+ if (s3 != NULL)
+ s4 = strstr (s3, "::NoSuchStrinG");
+ if (s3 == NULL || s4 == NULL)
+ {
+ stab_bad_demangle (orig);
+ if (s3 != NULL)
+ free (s3);
+ return FALSE;
+ }
+
+ /* 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 (s3, to - s3);
+
+ free (s3);
+ }
+
+ return TRUE;
+}
+
+/* Demangle a class name. */
+
+static bfd_boolean
+stab_demangle_class (struct stab_demangle_info *minfo ATTRIBUTE_UNUSED,
+ const char **pp, const char **pstart)
+{
+ const char *orig;
+ unsigned int n;
+
+ orig = *pp;
+
+ n = stab_demangle_count (pp);
+ if (strlen (*pp) < n)
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+
+ if (pstart != NULL)
+ *pstart = *pp;
+
+ *pp += n;
+
+ return TRUE;
+}
+
+/* Demangle function arguments. If the pargs argument is not NULL, it
+ is set to a NULL terminated array holding the arguments. */
+
+static bfd_boolean
+stab_demangle_args (struct stab_demangle_info *minfo, const char **pp,
+ debug_type **pargs, bfd_boolean *pvarargs)
+{
+ const char *orig;
+ unsigned int alloc, count;
+
+ orig = *pp;
+
+ alloc = 10;
+ if (pargs != NULL)
+ {
+ *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs);
+ *pvarargs = FALSE;
+ }
+ count = 0;
+
+ while (**pp != '_' && **pp != '\0' && **pp != 'e')
+ {
+ if (**pp == 'N' || **pp == 'T')
+ {
+ char temptype;
+ unsigned int r, t;
+
+ temptype = **pp;
+ ++*pp;
+
+ if (temptype == 'T')
+ r = 1;
+ else
+ {
+ if (! stab_demangle_get_count (pp, &r))
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ }
+
+ if (! stab_demangle_get_count (pp, &t))
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+
+ if (t >= minfo->typestring_count)
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ while (r-- > 0)
+ {
+ const char *tem;
+
+ tem = minfo->typestrings[t].typestring;
+ if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc))
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc))
+ return FALSE;
+ }
+ }
+
+ if (pargs != NULL)
+ (*pargs)[count] = DEBUG_TYPE_NULL;
+
+ if (**pp == 'e')
+ {
+ if (pargs != NULL)
+ *pvarargs = TRUE;
+ ++*pp;
+ }
+
+ return TRUE;
+}
+
+/* Demangle a single argument. */
+
+static bfd_boolean
+stab_demangle_arg (struct stab_demangle_info *minfo, const char **pp,
+ debug_type **pargs, unsigned int *pcount,
+ unsigned int *palloc)
+{
+ const char *start;
+ debug_type type;
+
+ start = *pp;
+ if (! stab_demangle_type (minfo, pp,
+ pargs == NULL ? (debug_type *) NULL : &type)
+ || ! stab_demangle_remember_type (minfo, start, *pp - start))
+ return FALSE;
+
+ if (pargs != NULL)
+ {
+ if (type == DEBUG_TYPE_NULL)
+ return FALSE;
+
+ if (*pcount + 1 >= *palloc)
+ {
+ *palloc += 10;
+ *pargs = ((debug_type *)
+ xrealloc (*pargs, *palloc * sizeof **pargs));
+ }
+ (*pargs)[*pcount] = type;
+ ++*pcount;
+ }
+
+ return TRUE;
+}
+
+/* Demangle a type. If the ptype argument is not NULL, *ptype is set
+ to the newly allocated type. */
+
+static bfd_boolean
+stab_demangle_type (struct stab_demangle_info *minfo, const char **pp,
+ debug_type *ptype)
+{
+ const char *orig;
+
+ orig = *pp;
+
+ switch (**pp)
+ {
+ case 'P':
+ case 'p':
+ /* A pointer type. */
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return FALSE;
+ if (ptype != NULL)
+ *ptype = debug_make_pointer_type (minfo->dhandle, *ptype);
+ break;
+
+ case 'R':
+ /* A reference type. */
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return FALSE;
+ if (ptype != NULL)
+ *ptype = debug_make_reference_type (minfo->dhandle, *ptype);
+ break;
+
+ case 'A':
+ /* An array. */
+ {
+ unsigned long high;
+
+ ++*pp;
+ high = 0;
+ while (**pp != '\0' && **pp != '_')
+ {
+ if (! ISDIGIT (**pp))
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ high *= 10;
+ high += **pp - '0';
+ ++*pp;
+ }
+ if (**pp != '_')
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ ++*pp;
+
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return FALSE;
+ if (ptype != NULL)
+ {
+ debug_type int_type;
+
+ int_type = debug_find_named_type (minfo->dhandle, "int");
+ if (int_type == NULL)
+ int_type = debug_make_int_type (minfo->dhandle, 4, FALSE);
+ *ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type,
+ 0, high, FALSE);
+ }
+ }
+ break;
+
+ case 'T':
+ /* A back reference to a remembered type. */
+ {
+ unsigned int i;
+ const char *p;
+
+ ++*pp;
+ if (! stab_demangle_get_count (pp, &i))
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ if (i >= minfo->typestring_count)
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ p = minfo->typestrings[i].typestring;
+ if (! stab_demangle_type (minfo, &p, ptype))
+ return FALSE;
+ }
+ break;
+
+ case 'F':
+ /* A function. */
+ {
+ debug_type *args;
+ bfd_boolean varargs;
+
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp,
+ (ptype == NULL
+ ? (debug_type **) NULL
+ : &args),
+ (ptype == NULL
+ ? (bfd_boolean *) NULL
+ : &varargs)))
+ return FALSE;
+ if (**pp != '_')
+ {
+ /* cplus_demangle will accept a function without a return
+ type, but I don't know when that will happen, or what
+ to do if it does. */
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return FALSE;
+ if (ptype != NULL)
+ *ptype = debug_make_function_type (minfo->dhandle, *ptype, args,
+ varargs);
+
+ }
+ break;
+
+ case 'M':
+ case 'O':
+ {
+ bfd_boolean memberp;
+ debug_type class_type = DEBUG_TYPE_NULL;
+ debug_type *args;
+ bfd_boolean varargs;
+ unsigned int n;
+ const char *name;
+
+ memberp = **pp == 'M';
+ args = NULL;
+ varargs = FALSE;
+
+ ++*pp;
+ if (ISDIGIT (**pp))
+ {
+ n = stab_demangle_count (pp);
+ if (strlen (*pp) < n)
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ name = *pp;
+ *pp += n;
+
+ if (ptype != NULL)
+ {
+ class_type = stab_find_tagged_type (minfo->dhandle,
+ minfo->info,
+ name, (int) n,
+ DEBUG_KIND_CLASS);
+ if (class_type == DEBUG_TYPE_NULL)
+ return FALSE;
+ }
+ }
+ else if (**pp == 'Q')
+ {
+ if (! stab_demangle_qualified (minfo, pp,
+ (ptype == NULL
+ ? (debug_type *) NULL
+ : &class_type)))
+ return FALSE;
+ }
+ else
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+
+ if (memberp)
+ {
+ if (**pp == 'C')
+ {
+ ++*pp;
+ }
+ else if (**pp == 'V')
+ {
+ ++*pp;
+ }
+ if (**pp != 'F')
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp,
+ (ptype == NULL
+ ? (debug_type **) NULL
+ : &args),
+ (ptype == NULL
+ ? (bfd_boolean *) NULL
+ : &varargs)))
+ return FALSE;
+ }
+
+ if (**pp != '_')
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ ++*pp;
+
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return FALSE;
+
+ if (ptype != NULL)
+ {
+ if (! memberp)
+ *ptype = debug_make_offset_type (minfo->dhandle, class_type,
+ *ptype);
+ else
+ {
+ /* FIXME: We have no way to record constp or
+ volatilep. */
+ *ptype = debug_make_method_type (minfo->dhandle, *ptype,
+ class_type, args, varargs);
+ }
+ }
+ }
+ break;
+
+ case 'G':
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return FALSE;
+ break;
+
+ case 'C':
+ ++*pp;
+ if (! stab_demangle_type (minfo, pp, ptype))
+ return FALSE;
+ if (ptype != NULL)
+ *ptype = debug_make_const_type (minfo->dhandle, *ptype);
+ break;
+
+ case 'Q':
+ {
+ if (! stab_demangle_qualified (minfo, pp, ptype))
+ return FALSE;
+ }
+ break;
+
+ default:
+ if (! stab_demangle_fund_type (minfo, pp, ptype))
+ return FALSE;
+ break;
+ }
+
+ return TRUE;
+}
+
+/* Demangle a fundamental type. If the ptype argument is not NULL,
+ *ptype is set to the newly allocated type. */
+
+static bfd_boolean
+stab_demangle_fund_type (struct stab_demangle_info *minfo, const char **pp,
+ debug_type *ptype)
+{
+ const char *orig;
+ bfd_boolean constp, volatilep, unsignedp, signedp;
+ bfd_boolean done;
+
+ orig = *pp;
+
+ constp = FALSE;
+ volatilep = FALSE;
+ unsignedp = FALSE;
+ signedp = FALSE;
+
+ done = FALSE;
+ while (! done)
+ {
+ switch (**pp)
+ {
+ case 'C':
+ constp = TRUE;
+ ++*pp;
+ break;
+
+ case 'U':
+ unsignedp = TRUE;
+ ++*pp;
+ break;
+
+ case 'S':
+ signedp = TRUE;
+ ++*pp;
+ break;
+
+ case 'V':
+ volatilep = TRUE;
+ ++*pp;
+ break;
+
+ default:
+ done = TRUE;
+ break;
+ }
+ }
+
+ switch (**pp)
+ {
+ case '\0':
+ case '_':
+ /* cplus_demangle permits this, but I don't know what it means. */
+ stab_bad_demangle (orig);
+ break;
+
+ case 'v': /* void */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "void");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_void_type (minfo->dhandle);
+ }
+ ++*pp;
+ break;
+
+ case 'x': /* long long */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "long long unsigned int"
+ : "long long int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'l': /* long */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "long unsigned int"
+ : "long int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'i': /* int */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "unsigned int"
+ : "int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 's': /* short */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "short unsigned int"
+ : "short int"));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'b': /* bool */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "bool");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_bool_type (minfo->dhandle, 4);
+ }
+ ++*pp;
+ break;
+
+ case 'c': /* char */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle,
+ (unsignedp
+ ? "unsigned char"
+ : (signedp
+ ? "signed char"
+ : "char")));
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp);
+ }
+ ++*pp;
+ break;
+
+ case 'w': /* wchar_t */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "__wchar_t");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_int_type (minfo->dhandle, 2, TRUE);
+ }
+ ++*pp;
+ break;
+
+ case 'r': /* long double */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "long double");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_float_type (minfo->dhandle, 8);
+ }
+ ++*pp;
+ break;
+
+ case 'd': /* double */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "double");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_float_type (minfo->dhandle, 8);
+ }
+ ++*pp;
+ break;
+
+ case 'f': /* float */
+ if (ptype != NULL)
+ {
+ *ptype = debug_find_named_type (minfo->dhandle, "float");
+ if (*ptype == DEBUG_TYPE_NULL)
+ *ptype = debug_make_float_type (minfo->dhandle, 4);
+ }
+ ++*pp;
+ break;
+
+ case 'G':
+ ++*pp;
+ if (! ISDIGIT (**pp))
+ {
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+ /* Fall through. */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ const char *hold;
+
+ if (! stab_demangle_class (minfo, pp, &hold))
+ return FALSE;
+ if (ptype != NULL)
+ {
+ char *name;
+
+ name = savestring (hold, *pp - hold);
+ *ptype = debug_find_named_type (minfo->dhandle, name);
+ free (name);
+ if (*ptype == DEBUG_TYPE_NULL)
+ {
+ /* FIXME: It is probably incorrect to assume that
+ undefined types are tagged types. */
+ *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
+ hold, *pp - hold,
+ DEBUG_KIND_ILLEGAL);
+ if (*ptype == DEBUG_TYPE_NULL)
+ return FALSE;
+ }
+ }
+ }
+ break;
+
+ case 't':
+ {
+ char *name;
+
+ if (! stab_demangle_template (minfo, pp,
+ ptype != NULL ? &name : NULL))
+ return FALSE;
+ if (ptype != NULL)
+ {
+ *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
+ name, strlen (name),
+ DEBUG_KIND_CLASS);
+ free (name);
+ if (*ptype == DEBUG_TYPE_NULL)
+ return FALSE;
+ }
+ }
+ break;
+
+ default:
+ stab_bad_demangle (orig);
+ return FALSE;
+ }
+
+ if (ptype != NULL)
+ {
+ if (constp)
+ *ptype = debug_make_const_type (minfo->dhandle, *ptype);
+ if (volatilep)
+ *ptype = debug_make_volatile_type (minfo->dhandle, *ptype);
+ }
+
+ return TRUE;
+}
+
+/* Remember a type string in a demangled string. */
+
+static bfd_boolean
+stab_demangle_remember_type (struct stab_demangle_info *minfo,
+ const char *p, int len)
+{
+ if (minfo->typestring_count >= minfo->typestring_alloc)
+ {
+ minfo->typestring_alloc += 10;
+ minfo->typestrings = ((struct stab_demangle_typestring *)
+ xrealloc (minfo->typestrings,
+ (minfo->typestring_alloc
+ * sizeof *minfo->typestrings)));
+ }
+
+ minfo->typestrings[minfo->typestring_count].typestring = p;
+ minfo->typestrings[minfo->typestring_count].len = (unsigned int) len;
+ ++minfo->typestring_count;
+
+ return TRUE;
+}
+\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, bfd_boolean *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,
+ bfd_boolean *pvarargs)
+{
+ struct demangle_component *dc;
+ unsigned int alloc, count;
+ debug_type *pargs;
+
+ alloc = 10;
+ pargs = (debug_type *) xmalloc (alloc * sizeof *pargs);
+ *pvarargs = FALSE;
+
+ count = 0;
+
+ for (dc = arglist;
+ dc != NULL;
+ dc = dc->u.s_binary.right)
+ {
+ debug_type arg;
+ bfd_boolean varargs;
+
+ if (dc->type != DEMANGLE_COMPONENT_ARGLIST)
+ {
+ fprintf (stderr, _("Unexpected type in v3 arglist demangling\n"));
+ free (pargs);
+ return NULL;
+ }
+
+ /* 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 = (debug_type *) xrealloc (pargs, alloc * sizeof *pargs);
+ }
+
+ pargs[count] = arg;
+ ++count;
+ }
+
+ pargs[count] = DEBUG_TYPE_NULL;
+
+ return pargs;
+}
+
+/* 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,
+ bfd_boolean *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;
+ bfd_boolean 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;
+ }
+ }
+}