/* stabs.c -- Parse stabs debugging information
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include "bfd.h"
#include "bucomm.h"
#include "libiberty.h"
+#include "demangle.h"
#include "debug.h"
#include "budbg.h"
struct stab_handle
{
- /* The type of the last stab symbol, so that we can detect N_SO
- pairs. */
- int last_type;
+ /* The BFD. */
+ bfd *abfd;
+ /* True if this is stabs in sections. */
+ boolean sections;
+ /* The symbol table. */
+ asymbol **syms;
+ /* The number of symbols. */
+ long symcount;
+ /* The accumulated file name string. */
+ char *so_string;
+ /* The value of the last N_SO symbol. */
+ bfd_vma so_value;
+ /* The value of the start of the file, so that we can handle file
+ relative N_LBRAC and N_RBRAC symbols. */
+ bfd_vma file_start_offset;
/* The offset of the start of the function, so that we can handle
- function relative N_RBRAC symbols. */
+ function relative N_LBRAC and N_RBRAC symbols. */
bfd_vma function_start_offset;
/* The version number of gcc which compiled the current compilation
unit, 0 if not compiled by gcc. */
struct bincl_file *bincl_stack;
/* Whether we are inside a function or not. */
boolean 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). */
+ bfd_vma function_end;
/* The depth of block nesting. */
int block_depth;
/* List of pending variable definitions. */
static boolean parse_stab_string
PARAMS ((PTR, struct stab_handle *, int, int, bfd_vma, const char *));
static debug_type parse_stab_type
- PARAMS ((PTR, struct stab_handle *, const char **, debug_type **));
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **,
+ debug_type **));
static boolean parse_stab_type_number
PARAMS ((const char **, int *));
static debug_type parse_stab_range_type
- PARAMS ((PTR, struct stab_handle *, const char **, const int *));
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **,
+ const int *));
static debug_type parse_stab_sun_builtin_type PARAMS ((PTR, 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 **));
static debug_type parse_stab_struct_type
- PARAMS ((PTR, struct stab_handle *, const char **, boolean, const int *));
+ 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 **, const char *,
debug_field *, boolean *));
static boolean parse_stab_members
- PARAMS ((PTR, struct stab_handle *, const char **, debug_method **));
+ PARAMS ((PTR, struct stab_handle *, const char *, const char **,
+ const int *, debug_method **));
+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 *));
PARAMS ((PTR, struct stab_handle *, const int *, debug_type));
static debug_type stab_xcoff_builtin_type
PARAMS ((PTR, struct stab_handle *, int));
+static debug_type stab_find_tagged_type
+ PARAMS ((PTR, struct stab_handle *, const char *, int,
+ enum debug_type_kind));
+static debug_type *stab_demangle_argtypes
+ PARAMS ((PTR, struct stab_handle *, const char *, boolean *));
/* Save a string in memory. */
/*ARGSUSED*/
PTR
-start_stab (dhandle)
+start_stab (dhandle, abfd, sections, syms, symcount)
PTR dhandle;
+ bfd *abfd;
+ boolean sections;
+ asymbol **syms;
+ long symcount;
{
struct stab_handle *ret;
ret = (struct stab_handle *) xmalloc (sizeof *ret);
memset (ret, 0, sizeof *ret);
+ ret->abfd = abfd;
+ ret->sections = sections;
+ ret->syms = syms;
+ ret->symcount = symcount;
ret->files = 1;
ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types);
ret->file_types[0] = NULL;
+ ret->function_end = (bfd_vma) -1;
return (PTR) ret;
}
if (info->within_function)
{
- if (! debug_end_function (dhandle, (bfd_vma) -1))
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, info->function_end))
return false;
info->within_function = false;
+ info->function_end = (bfd_vma) -1;
}
for (st = info->tags; st != NULL; st = st->next)
{
- st->slot = debug_make_undefined_tagged_type (dhandle, st->name,
- st->kind);
+ 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;
}
{
struct stab_handle *info = (struct stab_handle *) handle;
+ /* 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
+ strings as we see them, and start the new compilation unit when
+ we see a non N_SO symbol. */
+ if (info->so_string != NULL
+ && (type != N_SO || *string == '\0' || value != info->so_value))
+ {
+ if (! debug_set_filename (dhandle, info->so_string))
+ return false;
+ info->main_filename = info->so_string;
+
+ info->gcc_compiled = 0;
+ info->n_opt_found = false;
+
+ /* Generally, for stabs in the symbol table, the N_LBRAC and
+ N_RBRAC symbols are relative to the N_SO symbol value. */
+ if (! info->sections)
+ 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. */
+ info->files = 1;
+ info->file_types = ((struct stab_types **)
+ xmalloc (sizeof *info->file_types));
+ info->file_types[0] = NULL;
+
+ info->so_string = NULL;
+
+ /* Now process whatever type we just got. */
+ }
+
switch (type)
{
case N_FN:
}
/* Start an inner lexical block. */
- if (! debug_start_block (dhandle, value + info->function_start_offset))
+ if (! debug_start_block (dhandle,
+ (value
+ + info->file_start_offset
+ + info->function_start_offset)))
return false;
/* Emit any pending variable definitions. */
return false;
/* End an inner lexical block. */
- if (! debug_end_block (dhandle, value + info->function_start_offset))
+ if (! debug_end_block (dhandle,
+ (value
+ + info->file_start_offset
+ + info->function_start_offset)))
return false;
--info->block_depth;
- if (info->block_depth == 0)
+ if (info->block_depth < 0)
{
- info->within_function = false;
- if (! debug_end_function (dhandle,
- value + info->function_start_offset))
- return false;
+ fprintf (stderr, "Too many N_RBRACs\n");
+ return false;
}
break;
case N_SO:
- /* Start a file. If we get two in a row, the first is the
- directory name. An empty string is emitted by gcc at the end
- of a compilation unit. */
- if (*string == '\0')
- {
- if (info->within_function)
- {
- if (! debug_end_function (dhandle, (bfd_vma) -1))
- return false;
- info->within_function = false;
- }
- return true;
- }
- info->gcc_compiled = 0;
- info->n_opt_found = false;
- if (info->last_type == N_SO)
+ /* This always ends a function. */
+ if (info->within_function)
{
- char *o;
-
- if (! debug_append_filename (dhandle, string))
+ bfd_vma endval;
+
+ endval = value;
+ if (*string != '\0'
+ && info->function_end != (bfd_vma) -1
+ && info->function_end < endval)
+ endval = info->function_end;
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, endval))
return false;
- o = info->main_filename;
- info->main_filename = concat (o, string, (const char *) NULL);
- free (o);
+ info->within_function = false;
+ info->function_end = (bfd_vma) -1;
}
+
+ /* An empty string is emitted by gcc at the end of a compilation
+ unit. */
+ if (*string == '\0')
+ return true;
+
+ /* Just accumulate strings until we see a non N_SO symbol. If
+ the string starts with '/', we discard the previously
+ accumulated strings. */
+ if (info->so_string == NULL)
+ info->so_string = xstrdup (string);
else
{
- if (! debug_set_filename (dhandle, string))
- return false;
- if (info->main_filename != NULL)
- free (info->main_filename);
- info->main_filename = xstrdup (string);
+ char *f;
- /* 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. */
- info->files = 1;
- info->file_types = ((struct stab_types **)
- xmalloc (sizeof *info->file_types));
- info->file_types[0] = NULL;
+ f = info->so_string;
+ if (*string == '/')
+ info->so_string = xstrdup (string);
+ else
+ info->so_string = concat (info->so_string, string,
+ (const char *) NULL);
+ free (f);
}
+
+ info->so_value = value;
+
break;
case N_SOL:
return false;
break;
+ case N_FUN:
+ if (*string == '\0')
+ {
+ if (info->within_function)
+ {
+ /* This always marks the end of a function; we don't
+ need to worry about info->function_end. */
+ if (info->sections)
+ value += info->function_start_offset;
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, value))
+ return false;
+ info->within_function = false;
+ info->function_end = (bfd_vma) -1;
+ }
+ break;
+ }
+
+ /* A const static symbol in the .text section will have an N_FUN
+ entry. We need to use these to mark the end of the function,
+ in case we are looking at gcc output before it was changed to
+ always emit an empty N_FUN. We can't call debug_end_function
+ here, because it might be a local static symbol. */
+ if (info->within_function
+ && (info->function_end == (bfd_vma) -1
+ || value < info->function_end))
+ info->function_end = value;
+
+ /* Fall through. */
/* FIXME: gdb checks the string for N_STSYM, N_LCSYM or N_ROSYM
symbols, and if it does not start with :S, gdb relocates the
value to the start of the section. gcc always seems to use
:S, so we don't worry about this. */
+ /* Fall through. */
default:
{
const char *colon;
{
if (info->within_function)
{
- if (! debug_end_function (dhandle, (bfd_vma) -1))
+ bfd_vma endval;
+
+ endval = value;
+ if (info->function_end != (bfd_vma) -1
+ && info->function_end < endval)
+ endval = info->function_end;
+ if (! stab_emit_pending_vars (dhandle, info)
+ || ! debug_end_function (dhandle, endval))
return false;
+ info->function_end = (bfd_vma) -1;
}
- info->function_start_offset = value;
+ /* For stabs in sections, line numbers and block addresses
+ are offsets from the start of the function. */
+ if (info->sections)
+ info->function_start_offset = value;
info->within_function = true;
}
break;
}
- info->last_type = type;
-
return true;
}
can be represented as integral.
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, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL,
+ &p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (*p != ',')
case 'C':
/* The name of a caught exception. */
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL,
+ &p, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_label (dhandle, name, dtype, value))
case 'f':
case 'F':
/* A function definition. */
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_function (dhandle, name, dtype, type == 'F', value))
while (*p == ';')
{
++p;
- if (parse_stab_type (dhandle, info, &p, (debug_type **) NULL)
+ if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL)
== DEBUG_TYPE_NULL)
return false;
}
break;
case 'G':
- /* A global symbol. The value must be extracted from the symbol
- table. */
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
- if (dtype == DEBUG_TYPE_NULL)
- return false;
- if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
- (bfd_vma) -1))
- return false;
+ {
+ 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);
+ if (dtype == DEBUG_TYPE_NULL)
+ return false;
+ leading = bfd_get_symbol_leading_char (info->abfd);
+ for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
+ {
+ const char *n;
+
+ n = bfd_asymbol_name (*ps);
+ if (leading != '\0' && *n == leading)
+ ++n;
+ if (*n == *name && strcmp (n, name) == 0)
+ break;
+ }
+ if (c > 0)
+ value = bfd_asymbol_value (*ps);
+ if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
+ value))
+ return false;
+ }
break;
/* This case is faked by a conditional above, when there is no
contains 'l'. */
case 'l':
case 's':
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
case 'p':
/* A function parameter. */
if (*p != 'F')
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
else
{
/* pF is a two-letter code that means a function parameter in
Fortran. The type-number specifies the type of the return
value. Translate it into a pointer-to-function type. */
++p;
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
if (dtype != DEBUG_TYPE_NULL)
- dtype = debug_make_pointer_type (dhandle,
- debug_make_function_type (dhandle,
- dtype));
+ {
+ debug_type ftype;
+
+ ftype = debug_make_function_type (dhandle, dtype,
+ (debug_type *) NULL, false);
+ dtype = debug_make_pointer_type (dhandle, ftype);
+ }
}
if (dtype == DEBUG_TYPE_NULL)
return false;
while (*p == ';')
{
++p;
- if (parse_stab_type (dhandle, info, &p, (debug_type **) NULL)
+ if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL)
== DEBUG_TYPE_NULL)
return false;
}
/* Fall through. */
case 'R':
/* Parameter which is in a register. */
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG,
case 'r':
/* Register variable (either global or local). */
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER,
case 'S':
/* Static symbol at top level of file */
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC,
case 't':
/* A typedef. */
- dtype = parse_stab_type (dhandle, info, &p, &slot);
+ dtype = parse_stab_type (dhandle, info, name, &p, &slot);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (name == NULL)
++p;
}
- dtype = parse_stab_type (dhandle, info, &p, &slot);
+ dtype = parse_stab_type (dhandle, info, name, &p, &slot);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (name == NULL)
case 'V':
/* Static symbol of local scope */
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
/* FIXME: gdb checks os9k_stabs here. */
case 'v':
/* Reference parameter. */
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE,
case 'a':
/* Reference parameter which is in a register. */
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG,
Sun claims ("dbx and dbxtool interfaces", 2nd ed)
that Pascal uses it too, but when I tried it Pascal used
"x:3" (local symbol) instead. */
- dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
+ (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return false;
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
return true;
}
-/* Parse a stabs type. */
+/* Parse a stabs type. The typename argument is non-NULL if this is a
+ typedef or a tag definition. The pp argument points to the stab
+ string, and is updated. The slotp argument points to a place to
+ store the slot used if the type is being defined. */
static debug_type
-parse_stab_type (dhandle, info, pp, slotp)
+parse_stab_type (dhandle, info, typename, pp, slotp)
PTR dhandle;
struct stab_handle *info;
+ const char *typename;
const char **pp;
debug_type **slotp;
{
{
enum debug_type_kind code;
const char *q1, *q2, *p;
- char *name;
- struct stab_tag *st;
/* A cross reference to another type. */
}
}
- name = savestring (*pp, p - *pp);
+ dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code);
*pp = p + 1;
-
- /* We pass DEBUG_KIND_VOID 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_VOID);
- if (dtype != DEBUG_TYPE_NULL)
- {
- free (name);
- if (typenums[0] != -1)
- {
- if (! stab_record_type (dhandle, info, typenums, dtype))
- return DEBUG_TYPE_NULL;
- }
- 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)
- 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 = code;
- st->slot = DEBUG_TYPE_NULL;
- st->type = debug_make_indirect_type (dhandle, &st->slot, name);
- info->tags = st;
- }
-
- dtype = st->type;
- if (typenums[0] != -1)
- {
- if (! stab_record_type (dhandle, info, typenums, dtype))
- return DEBUG_TYPE_NULL;
- }
- return dtype;
}
break;
/* Go back to the number and have parse_stab_type get it.
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, pp, (debug_type **) NULL);
+ dtype = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
case '*':
dtype = debug_make_pointer_type (dhandle,
- parse_stab_type (dhandle, info, pp,
+ parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
(debug_type **) NULL));
break;
/* Reference to another type. */
dtype = (debug_make_reference_type
(dhandle,
- parse_stab_type (dhandle, info, pp, (debug_type **) NULL)));
+ parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL)));
break;
case 'f':
/* FIXME: gdb checks os9k_stabs here. */
dtype = (debug_make_function_type
(dhandle,
- parse_stab_type (dhandle, info, pp, (debug_type **) NULL)));
+ parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL),
+ (debug_type *) NULL, false));
break;
case 'k':
/* Const qualifier on some type (Sun). */
/* FIXME: gdb accepts 'c' here if os9k_stabs. */
dtype = debug_make_const_type (dhandle,
- parse_stab_type (dhandle, info, pp,
+ parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
(debug_type **) NULL));
break;
/* FIXME: gdb accepts 'i' here if os9k_stabs. */
dtype = (debug_make_volatile_type
(dhandle,
- parse_stab_type (dhandle, info, pp, (debug_type **) NULL)));
+ parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL)));
break;
case '@':
/* Member type. */
- domain = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ domain = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
if (domain == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
++*pp;
- memtype = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
if (memtype == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
debug_type return_type;
++*pp;
- return_type = parse_stab_type (dhandle, info, pp,
- (debug_type **) NULL);
+ return_type = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
if (return_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
if (**pp != ';')
}
++*pp;
dtype = debug_make_method_type (dhandle, return_type,
- DEBUG_TYPE_NULL, NULL);
+ DEBUG_TYPE_NULL,
+ (debug_type *) NULL, false);
}
else
{
debug_type *args;
unsigned int n;
unsigned int alloc;
+ boolean varargs;
- domain = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ domain = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
if (domain == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
++*pp;
- return_type = parse_stab_type (dhandle, info, pp,
- (debug_type **) NULL);
+ return_type = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
if (return_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
xrealloc ((PTR) args, alloc * sizeof *args));
}
- args[n] = parse_stab_type (dhandle, info, pp,
- (debug_type **) NULL);
+ args[n] = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
if (args[n] == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
++n;
}
++*pp;
+ /* If the last type is not void, then this function takes a
+ variable number of arguments. Otherwise, we must strip
+ the void type. */
+ if (n == 0
+ || debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID)
+ varargs = true;
+ else
+ {
+ --n;
+ varargs = false;
+ }
+
args[n] = DEBUG_TYPE_NULL;
- dtype = debug_make_method_type (dhandle, return_type, domain, args);
+ dtype = debug_make_method_type (dhandle, return_type, domain, args,
+ varargs);
}
break;
case 'r':
/* Range type. */
- dtype = parse_stab_range_type (dhandle, info, pp, typenums);
+ dtype = parse_stab_range_type (dhandle, info, typename, pp, typenums);
break;
case 'b':
case 's':
case 'u':
/* Struct or union type. */
- dtype = parse_stab_struct_type (dhandle, info, pp,
+ dtype = parse_stab_struct_type (dhandle, info, typename, pp,
descriptor == 's', typenums);
break;
case 'S':
dtype = debug_make_set_type (dhandle,
- parse_stab_type (dhandle, info, pp,
+ parse_stab_type (dhandle, info,
+ (const char *) NULL,
+ pp,
(debug_type **) NULL),
stringp);
break;
/* Parse a range type. */
static debug_type
-parse_stab_range_type (dhandle, info, pp, typenums)
+parse_stab_range_type (dhandle, info, typename, pp, typenums)
PTR dhandle;
struct stab_handle *info;
+ const char *typename;
const char **pp;
const int *typenums;
{
if (**pp == '=')
{
*pp = orig;
- index_type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ index_type = parse_stab_type (dhandle, info, (const char *) NULL,
+ pp, (debug_type **) NULL);
if (index_type == DEBUG_TYPE_NULL)
return DEBUG_TYPE_NULL;
}
if (self_subrange && n2 == 0 && n3 == 0)
return debug_make_void_type (dhandle);
+ /* A type defined as a subrange of itself, with n2 positive and
+ n3 zero, is a complex type, and n2 is the number of bytes. */
+ if (self_subrange && n3 == 0 && n2 > 0)
+ return debug_make_complex_type (dhandle, n2);
+
/* If n3 is zero and n2 is positive, this is a floating point
type, and n2 is the number of bytes. */
if (n3 == 0 && n2 > 0)
/* If the upper bound is -1, this is an unsigned int. */
if (n2 == 0 && n3 == -1)
{
+ /* When gcc is used with -gstabs, but not -gstabs+, it will emit
+ 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 (strcmp (typename, "long long int") == 0)
+ return debug_make_int_type (dhandle, 8, false);
+ else if (strcmp (typename, "long long unsigned int") == 0)
+ return debug_make_int_type (dhandle, 8, true);
+ }
/* FIXME: The size here really depends upon the target. */
return debug_make_int_type (dhandle, 4, true);
}
*PP will point to "4a:1,0,32;;". */
static debug_type
-parse_stab_struct_type (dhandle, info, pp, structp, typenums)
+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;
/* 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, pp, &methods)
+ || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods)
|| ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase,
&ownvptr))
return DEBUG_TYPE_NULL;
}
++*pp;
- type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
return false;
after is a regular type definition. Lookup the type, find it's
name, and construct the field name. */
- context = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ context = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
if (context == DEBUG_TYPE_NULL)
return false;
}
++*pp;
- type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
if (**pp != ',')
{
bad_stab (orig);
++*pp;
}
- type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
return false;
name (such as `+=') and `.' marks the end of the operator name. */
static boolean
-parse_stab_members (dhandle, info, pp, retp)
+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;
{
const char *orig;
do
{
debug_type type;
+ boolean stub;
char *argtypes;
enum debug_visibility visibility;
boolean constp, volatilep, staticp;
bfd_vma voffset;
debug_type context;
+ const char *physname;
+ boolean varargs;
if (look_ahead_type != DEBUG_TYPE_NULL)
{
}
else
{
- type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
if (type == DEBUG_TYPE_NULL)
return false;
if (**pp != ':')
return false;
}
- /* FIXME: gdb sets is_stub here. */
+ stub = false;
+ if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD
+ && debug_get_parameter_types (dhandle, type, &varargs) == NULL)
+ stub = true;
argtypes = savestring (*pp, p - *pp);
*pp = p + 1;
{
case '*':
/* virtual member function, followed by index. The sign
- bit is set to distinguish pointers-to-methods from
- virtual function indicies. Since the array is in
- words, the quantity must be shifted left by 1 on 16
- bit machine, and by 2 on 32 bit machine, forcing the
- sign bit out, and usable as a valid index into the
- array. Remove the sign bit here. */
+ bit is supposedly set to distinguish
+ pointers-to-methods from virtual function indicies. */
++*pp;
voffset = parse_number (pp, (boolean *) NULL);
if (**pp != ';')
}
++*pp;
voffset &= 0x7fffffff;
- voffset += 2;
if (**pp == ';' || *pp == '\0')
{
/* 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, pp,
+ 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
{
++*pp;
staticp = true;
voffset = 0;
- /* FIXME: gdb sets is_stub here. */
context = DEBUG_TYPE_NULL;
+ if (strncmp (argtypes, name, strlen (name)) != 0)
+ stub = true;
break;
default:
break;
}
+ /* If the type is not a stub, then the argtypes string is
+ the physical name of the function. Otherwise the
+ 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
+ {
+ debug_type class_type, return_type;
+
+ class_type = stab_find_type (dhandle, info, typenums);
+ if (class_type == DEBUG_TYPE_NULL)
+ return false;
+ return_type = debug_get_return_type (dhandle, type);
+ if (return_type == DEBUG_TYPE_NULL)
+ {
+ bad_stab (orig);
+ return false;
+ }
+ type = parse_stab_argtypes (dhandle, info, class_type, name,
+ tagname, return_type, argtypes,
+ constp, volatilep, &physname);
+ if (type == DEBUG_TYPE_NULL)
+ return false;
+ }
+
if (cvars + 1 >= allocvars)
{
allocvars += 10;
}
if (! staticp)
- variants[cvars] = debug_make_method_variant (dhandle, argtypes,
+ variants[cvars] = debug_make_method_variant (dhandle, physname,
type, visibility,
constp, volatilep,
voffset, context);
else
variants[cvars] = debug_make_static_method_variant (dhandle,
- argtypes,
+ physname,
type,
visibility,
constp,
return true;
}
+/* Parse a string representing argument types for a method. Stabs
+ tries to save space by packing argument types into a mangled
+ string. This string should give us enough information to extract
+ both argument types and the physical name of the function, given
+ 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;
+{
+ boolean is_full_physname_constructor;
+ boolean is_constructor;
+ boolean is_destructor;
+ debug_type *args;
+ boolean varargs;
+
+ /* Constructors are sometimes handled specially. */
+ is_full_physname_constructor = ((argtypes[0] == '_'
+ && argtypes[1] == '_'
+ && (isdigit ((unsigned char) argtypes[2])
+ || argtypes[2] == 'Q'
+ || argtypes[2] == 't'))
+ || strncmp (argtypes, "__ct", 4) == 0);
+
+ is_constructor = (is_full_physname_constructor
+ || (tagname != NULL
+ && strcmp (fieldname, tagname) == 0));
+ is_destructor = ((argtypes[0] == '_'
+ && (argtypes[1] == '$' || argtypes[1] == '.')
+ && argtypes[2] == '_')
+ || strncmp (argtypes, "__dt", 4) == 0);
+
+ if (is_destructor || is_full_physname_constructor)
+ *pphysname = argtypes;
+ else
+ {
+ unsigned int len;
+ const char *const_prefix;
+ const char *volatile_prefix;
+ char buf[20];
+ unsigned int mangled_name_len;
+ char *physname;
+
+ len = tagname == NULL ? 0 : strlen (tagname);
+ const_prefix = constp ? "C" : "";
+ volatile_prefix = volatilep ? "V" : "";
+
+ if (len == 0)
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ else if (tagname != NULL && strchr (tagname, '<') != NULL)
+ {
+ /* Template methods are fully mangled. */
+ sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
+ tagname = NULL;
+ len = 0;
+ }
+ else
+ sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len);
+
+ mangled_name_len = ((is_constructor ? 0 : strlen (fieldname))
+ + strlen (buf)
+ + len
+ + strlen (argtypes)
+ + 1);
+
+ if (fieldname[0] == 'o'
+ && fieldname[1] == 'p'
+ && (fieldname[2] == '$' || fieldname[2] == '.'))
+ {
+ const char *opname;
+
+ opname = cplus_mangle_opname (fieldname + 3, 0);
+ if (opname == NULL)
+ {
+ fprintf (stderr, "No mangling for \"%s\"\n", fieldname);
+ return DEBUG_TYPE_NULL;
+ }
+ mangled_name_len += strlen (opname);
+ physname = (char *) xmalloc (mangled_name_len);
+ strncpy (physname, fieldname, 3);
+ strcpy (physname + 3, opname);
+ }
+ else
+ {
+ physname = (char *) xmalloc (mangled_name_len);
+ if (is_constructor)
+ physname[0] = '\0';
+ else
+ strcpy (physname, fieldname);
+ }
+
+ strcat (physname, buf);
+ if (tagname != NULL)
+ strcat (physname, tagname);
+ strcat (physname, argtypes);
+
+ *pphysname = physname;
+ }
+
+ if (*argtypes == '\0')
+ {
+ args = (debug_type *) xmalloc (sizeof *args);
+ *args = NULL;
+ return debug_make_method_type (dhandle, return_type, class_type, args,
+ false);
+ }
+
+ args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs);
+ if (args == NULL)
+ return DEBUG_TYPE_NULL;
+
+ return debug_make_method_type (dhandle, return_type, class_type, args,
+ varargs);
+}
+
/* The tail end of stabs for C++ classes that contain a virtual function
pointer contains a tilde, a %, and a type number.
The type number refers to the base class (possibly this class itself) which
*pp = hold;
- vtype = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
for (p = *pp; *p != ';' && *p != '\0'; p++)
;
if (*p != ';')
boolean stringp;
{
const char *orig;
+ const char *p;
+ int typenums[2];
debug_type index_type;
boolean adjustable;
bfd_signed_vma lower, upper;
/* FIXME: gdb checks os9k_stabs here. */
- index_type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ /* If the index type is type 0, we take it as int. */
+ p = *pp;
+ if (! parse_stab_type_number (&p, typenums))
+ return false;
+ if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=')
+ {
+ index_type = debug_find_named_type (dhandle, "int");
+ if (index_type == DEBUG_TYPE_NULL)
+ {
+ index_type = debug_make_int_type (dhandle, 4, false);
+ if (index_type == DEBUG_TYPE_NULL)
+ return false;
+ }
+ *pp = p;
+ }
+ else
+ {
+ index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
+ }
+
if (**pp != ';')
{
bad_stab (orig);
}
++*pp;
- element_type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL);
+ element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
+ (debug_type **) NULL);
if (element_type == DEBUG_TYPE_NULL)
return false;
{
struct stab_pending_var *v;
- if (! info->within_function
+ if ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC)
+ || ! info->within_function
|| (info->gcc_compiled == 0 && info->n_opt_found))
return debug_record_variable (dhandle, name, type, kind, val);
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;
+{
+ 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. */
+ PTR 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;
+ /* 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 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));
+
+/* Warn about a bad demangling. */
+
+static void
+stab_bad_demangle (s)
+ const char *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;
+{
+ unsigned int count;
+
+ count = 0;
+ while (isdigit ((unsigned char) **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 boolean
+stab_demangle_get_count (pp, pi)
+ const char **pp;
+ unsigned int *pi;
+{
+ if (! isdigit ((unsigned char) **pp))
+ return false;
+
+ *pi = **pp - '0';
+ ++*pp;
+ if (isdigit ((unsigned char) **pp))
+ {
+ unsigned int count;
+ const char *p;
+
+ count = *pi;
+ p = *pp;
+ do
+ {
+ count *= 10;
+ count += *p - '0';
+ ++p;
+ }
+ while (isdigit ((unsigned char) *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 (dhandle, info, physname, pvarargs)
+ PTR dhandle;
+ struct stab_handle *info;
+ const char *physname;
+ boolean *pvarargs;
+{
+ struct stab_demangle_info minfo;
+
+ 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))
+ 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 boolean
+stab_demangle_prefix (minfo, pp)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+{
+ 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
+ {
+ 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 ((unsigned char) 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 ((unsigned char) 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 boolean
+stab_demangle_function_name (minfo, pp, scan)
+ 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
+ && strncmp (name, "type", 4) == 0
+ && (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 boolean
+stab_demangle_signature (minfo, pp)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+{
+ const char *orig;
+ 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)
+ || ! 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 boolean
+stab_demangle_qualified (minfo, pp, ptype)
+ 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 ((unsigned char) *p) || *p == '0')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ qualifiers = atoi (p);
+ while (isdigit ((unsigned char) *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')
+ {
+ /* FIXME: I don't know how to handle the ptype != NULL case
+ here. */
+ if (! stab_demangle_template (minfo, pp))
+ 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)
+ 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. */
+
+static boolean
+stab_demangle_template (minfo, pp)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+{
+ 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;
+ boolean pointerp, realp, integralp, charp, boolp;
+ 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 ((unsigned char) **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 ((unsigned char) **pp))
+ ++*pp;
+ if (**pp == '.')
+ {
+ ++*pp;
+ while (isdigit ((unsigned char) **pp))
+ ++*pp;
+ }
+ if (**pp == 'e')
+ {
+ ++*pp;
+ while (isdigit ((unsigned char) **pp))
+ ++*pp;
+ }
+ }
+ else if (pointerp)
+ {
+ unsigned int len;
+
+ if (! stab_demangle_get_count (pp, &len))
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ *pp += len;
+ }
+ }
+ }
+
+ 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;
+{
+ 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 boolean
+stab_demangle_args (minfo, pp, pargs, pvarargs)
+ struct stab_demangle_info *minfo;
+ const char **pp;
+ debug_type **pargs;
+ 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 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;
+{
+ 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 boolean
+stab_demangle_type (minfo, pp, ptype)
+ 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 ((unsigned char) **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;
+ boolean varargs;
+
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp,
+ (ptype == NULL
+ ? (debug_type **) NULL
+ : &args),
+ (ptype == NULL
+ ? (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':
+ {
+ boolean memberp, constp, volatilep;
+ debug_type *args;
+ boolean varargs;
+ unsigned int n;
+ const char *name;
+
+ memberp = **pp == 'M';
+ constp = false;
+ volatilep = false;
+ args = NULL;
+ varargs = false;
+
+ ++*pp;
+ if (! isdigit ((unsigned char) **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 (memberp)
+ {
+ if (**pp == 'C')
+ {
+ constp = true;
+ ++*pp;
+ }
+ else if (**pp == 'V')
+ {
+ volatilep = true;
+ ++*pp;
+ }
+ if (**pp != 'F')
+ {
+ stab_bad_demangle (orig);
+ return false;
+ }
+ ++*pp;
+ if (! stab_demangle_args (minfo, pp,
+ (ptype == NULL
+ ? (debug_type **) NULL
+ : &args),
+ (ptype == NULL
+ ? (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)
+ {
+ 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);
+ 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':
+ {
+ const char *hold;
+
+ hold = *pp;
+ if (! stab_demangle_qualified (minfo, pp, ptype))
+ return false;
+ }
+ break;
+
+ default:
+ if (! stab_demangle_fund_type (minfo, pp, ptype))
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+/* 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;
+{
+ const char *orig;
+ boolean constp, volatilep, unsignedp, signedp;
+ 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 ((unsigned char) **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);
+ 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);
+ }
+ 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;
+ }
+ 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 boolean
+stab_demangle_remember_type (minfo, p, len)
+ 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;
+}