OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [binutils-2.20.1/] [binutils/] [stabs.c] - Diff between revs 816 and 818

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 816 Rev 818
/* stabs.c -- Parse stabs debugging information
/* stabs.c -- Parse stabs debugging information
   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
   2005, 2006, 2007, 2008  Free Software Foundation, Inc.
   2005, 2006, 2007, 2008  Free Software Foundation, Inc.
   Written by Ian Lance Taylor <ian@cygnus.com>.
   Written by Ian Lance Taylor <ian@cygnus.com>.
 
 
   This file is part of GNU Binutils.
   This file is part of GNU Binutils.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
   02110-1301, USA.  */
   02110-1301, USA.  */
 
 
/* This file contains code which parses stabs debugging information.
/* This file contains code which parses stabs debugging information.
   The organization of this code is based on the gdb stabs reading
   The organization of this code is based on the gdb stabs reading
   code.  The job it does is somewhat different, because it is not
   code.  The job it does is somewhat different, because it is not
   trying to identify the correct address for anything.  */
   trying to identify the correct address for anything.  */
 
 
#include "sysdep.h"
#include "sysdep.h"
#include "bfd.h"
#include "bfd.h"
#include "libiberty.h"
#include "libiberty.h"
#include "safe-ctype.h"
#include "safe-ctype.h"
#include "demangle.h"
#include "demangle.h"
#include "debug.h"
#include "debug.h"
#include "budbg.h"
#include "budbg.h"
#include "filenames.h"
#include "filenames.h"
#include "aout/aout64.h"
#include "aout/aout64.h"
#include "aout/stab_gnu.h"
#include "aout/stab_gnu.h"
 
 
/* The number of predefined XCOFF types.  */
/* The number of predefined XCOFF types.  */
 
 
#define XCOFF_TYPE_COUNT 34
#define XCOFF_TYPE_COUNT 34
 
 
/* This structure is used as a handle so that the stab parsing doesn't
/* This structure is used as a handle so that the stab parsing doesn't
   need to use any static variables.  */
   need to use any static variables.  */
 
 
struct stab_handle
struct stab_handle
{
{
  /* The BFD.  */
  /* The BFD.  */
  bfd *abfd;
  bfd *abfd;
  /* TRUE if this is stabs in sections.  */
  /* TRUE if this is stabs in sections.  */
  bfd_boolean sections;
  bfd_boolean sections;
  /* The symbol table.  */
  /* The symbol table.  */
  asymbol **syms;
  asymbol **syms;
  /* The number of symbols.  */
  /* The number of symbols.  */
  long symcount;
  long symcount;
  /* The accumulated file name string.  */
  /* The accumulated file name string.  */
  char *so_string;
  char *so_string;
  /* The value of the last N_SO symbol.  */
  /* The value of the last N_SO symbol.  */
  bfd_vma so_value;
  bfd_vma so_value;
  /* The value of the start of the file, so that we can handle file
  /* The value of the start of the file, so that we can handle file
     relative N_LBRAC and N_RBRAC symbols.  */
     relative N_LBRAC and N_RBRAC symbols.  */
  bfd_vma file_start_offset;
  bfd_vma file_start_offset;
  /* The offset of the start of the function, so that we can handle
  /* The offset of the start of the function, so that we can handle
     function relative N_LBRAC and N_RBRAC symbols.  */
     function relative N_LBRAC and N_RBRAC symbols.  */
  bfd_vma function_start_offset;
  bfd_vma function_start_offset;
  /* The version number of gcc which compiled the current compilation
  /* The version number of gcc which compiled the current compilation
     unit, 0 if not compiled by gcc.  */
     unit, 0 if not compiled by gcc.  */
  int gcc_compiled;
  int gcc_compiled;
  /* Whether an N_OPT symbol was seen that was not generated by gcc,
  /* Whether an N_OPT symbol was seen that was not generated by gcc,
     so that we can detect the SunPRO compiler.  */
     so that we can detect the SunPRO compiler.  */
  bfd_boolean n_opt_found;
  bfd_boolean n_opt_found;
  /* The main file name.  */
  /* The main file name.  */
  char *main_filename;
  char *main_filename;
  /* A stack of unfinished N_BINCL files.  */
  /* A stack of unfinished N_BINCL files.  */
  struct bincl_file *bincl_stack;
  struct bincl_file *bincl_stack;
  /* A list of finished N_BINCL files.  */
  /* A list of finished N_BINCL files.  */
  struct bincl_file *bincl_list;
  struct bincl_file *bincl_list;
  /* Whether we are inside a function or not.  */
  /* Whether we are inside a function or not.  */
  bfd_boolean within_function;
  bfd_boolean within_function;
  /* The address of the end of the function, used if we have seen an
  /* 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
     N_FUN symbol while in a function.  This is -1 if we have not seen
     an N_FUN (the normal case).  */
     an N_FUN (the normal case).  */
  bfd_vma function_end;
  bfd_vma function_end;
  /* The depth of block nesting.  */
  /* The depth of block nesting.  */
  int block_depth;
  int block_depth;
  /* List of pending variable definitions.  */
  /* List of pending variable definitions.  */
  struct stab_pending_var *pending;
  struct stab_pending_var *pending;
  /* Number of files for which we have types.  */
  /* Number of files for which we have types.  */
  unsigned int files;
  unsigned int files;
  /* Lists of types per file.  */
  /* Lists of types per file.  */
  struct stab_types **file_types;
  struct stab_types **file_types;
  /* Predefined XCOFF types.  */
  /* Predefined XCOFF types.  */
  debug_type xcoff_types[XCOFF_TYPE_COUNT];
  debug_type xcoff_types[XCOFF_TYPE_COUNT];
  /* Undefined tags.  */
  /* Undefined tags.  */
  struct stab_tag *tags;
  struct stab_tag *tags;
  /* Set by parse_stab_type if it sees a structure defined as a cross
  /* Set by parse_stab_type if it sees a structure defined as a cross
     reference to itself.  Reset by parse_stab_type otherwise.  */
     reference to itself.  Reset by parse_stab_type otherwise.  */
  bfd_boolean self_crossref;
  bfd_boolean self_crossref;
};
};
 
 
/* A list of these structures is used to hold pending variable
/* A list of these structures is used to hold pending variable
   definitions seen before the N_LBRAC of a block.  */
   definitions seen before the N_LBRAC of a block.  */
 
 
struct stab_pending_var
struct stab_pending_var
{
{
  /* Next pending variable definition.  */
  /* Next pending variable definition.  */
  struct stab_pending_var *next;
  struct stab_pending_var *next;
  /* Name.  */
  /* Name.  */
  const char *name;
  const char *name;
  /* Type.  */
  /* Type.  */
  debug_type type;
  debug_type type;
  /* Kind.  */
  /* Kind.  */
  enum debug_var_kind kind;
  enum debug_var_kind kind;
  /* Value.  */
  /* Value.  */
  bfd_vma val;
  bfd_vma val;
};
};
 
 
/* A list of these structures is used to hold the types for a single
/* A list of these structures is used to hold the types for a single
   file.  */
   file.  */
 
 
struct stab_types
struct stab_types
{
{
  /* Next set of slots for this file.  */
  /* Next set of slots for this file.  */
  struct stab_types *next;
  struct stab_types *next;
  /* Types indexed by type number.  */
  /* Types indexed by type number.  */
#define STAB_TYPES_SLOTS (16)
#define STAB_TYPES_SLOTS (16)
  debug_type types[STAB_TYPES_SLOTS];
  debug_type types[STAB_TYPES_SLOTS];
};
};
 
 
/* We keep a list of undefined tags that we encounter, so that we can
/* We keep a list of undefined tags that we encounter, so that we can
   fill them in if the tag is later defined.  */
   fill them in if the tag is later defined.  */
 
 
struct stab_tag
struct stab_tag
{
{
  /* Next undefined tag.  */
  /* Next undefined tag.  */
  struct stab_tag *next;
  struct stab_tag *next;
  /* Tag name.  */
  /* Tag name.  */
  const char *name;
  const char *name;
  /* Type kind.  */
  /* Type kind.  */
  enum debug_type_kind kind;
  enum debug_type_kind kind;
  /* Slot to hold real type when we discover it.  If we don't, we fill
  /* Slot to hold real type when we discover it.  If we don't, we fill
     in an undefined tag type.  */
     in an undefined tag type.  */
  debug_type slot;
  debug_type slot;
  /* Indirect type we have created to point at slot.  */
  /* Indirect type we have created to point at slot.  */
  debug_type type;
  debug_type type;
};
};
 
 
static char *savestring (const char *, int);
static char *savestring (const char *, int);
static bfd_vma parse_number (const char **, bfd_boolean *);
static bfd_vma parse_number (const char **, bfd_boolean *);
static void bad_stab (const char *);
static void bad_stab (const char *);
static void warn_stab (const char *, const char *);
static void warn_stab (const char *, const char *);
static bfd_boolean parse_stab_string
static bfd_boolean parse_stab_string
  (void *, struct stab_handle *, int, int, bfd_vma, const char *);
  (void *, struct stab_handle *, int, int, bfd_vma, const char *);
static debug_type parse_stab_type
static debug_type parse_stab_type
  (void *, struct stab_handle *, const char *, const char **, debug_type **);
  (void *, struct stab_handle *, const char *, const char **, debug_type **);
static bfd_boolean parse_stab_type_number (const char **, int *);
static bfd_boolean parse_stab_type_number (const char **, int *);
static debug_type parse_stab_range_type
static debug_type parse_stab_range_type
  (void *, struct stab_handle *, const char *, const char **, const int *);
  (void *, struct stab_handle *, const char *, const char **, const int *);
static debug_type parse_stab_sun_builtin_type (void *, const char **);
static debug_type parse_stab_sun_builtin_type (void *, const char **);
static debug_type parse_stab_sun_floating_type (void *, const char **);
static debug_type parse_stab_sun_floating_type (void *, const char **);
static debug_type parse_stab_enum_type (void *, const char **);
static debug_type parse_stab_enum_type (void *, const char **);
static debug_type parse_stab_struct_type
static debug_type parse_stab_struct_type
  (void *, struct stab_handle *, const char *, const char **,
  (void *, struct stab_handle *, const char *, const char **,
   bfd_boolean, const int *);
   bfd_boolean, const int *);
static bfd_boolean parse_stab_baseclasses
static bfd_boolean parse_stab_baseclasses
  (void *, struct stab_handle *, const char **, debug_baseclass **);
  (void *, struct stab_handle *, const char **, debug_baseclass **);
static bfd_boolean parse_stab_struct_fields
static bfd_boolean parse_stab_struct_fields
  (void *, struct stab_handle *, const char **, debug_field **, bfd_boolean *);
  (void *, struct stab_handle *, const char **, debug_field **, bfd_boolean *);
static bfd_boolean parse_stab_cpp_abbrev
static bfd_boolean parse_stab_cpp_abbrev
  (void *, struct stab_handle *, const char **, debug_field *);
  (void *, struct stab_handle *, const char **, debug_field *);
static bfd_boolean parse_stab_one_struct_field
static bfd_boolean parse_stab_one_struct_field
  (void *, struct stab_handle *, const char **, const char *,
  (void *, struct stab_handle *, const char **, const char *,
   debug_field *, bfd_boolean *);
   debug_field *, bfd_boolean *);
static bfd_boolean parse_stab_members
static bfd_boolean parse_stab_members
  (void *, struct stab_handle *, const char *, const char **, const int *,
  (void *, struct stab_handle *, const char *, const char **, const int *,
   debug_method **);
   debug_method **);
static debug_type parse_stab_argtypes
static debug_type parse_stab_argtypes
  (void *, struct stab_handle *, debug_type, const char *, const char *,
  (void *, struct stab_handle *, debug_type, const char *, const char *,
   debug_type, const char *, bfd_boolean, bfd_boolean, const char **);
   debug_type, const char *, bfd_boolean, bfd_boolean, const char **);
static bfd_boolean parse_stab_tilde_field
static bfd_boolean parse_stab_tilde_field
  (void *, struct stab_handle *, const char **, const int *, debug_type *,
  (void *, struct stab_handle *, const char **, const int *, debug_type *,
   bfd_boolean *);
   bfd_boolean *);
static debug_type parse_stab_array_type
static debug_type parse_stab_array_type
  (void *, struct stab_handle *, const char **, bfd_boolean);
  (void *, struct stab_handle *, const char **, bfd_boolean);
static void push_bincl (struct stab_handle *, const char *, bfd_vma);
static void push_bincl (struct stab_handle *, const char *, bfd_vma);
static const char *pop_bincl (struct stab_handle *);
static const char *pop_bincl (struct stab_handle *);
static bfd_boolean find_excl (struct stab_handle *, const char *, bfd_vma);
static bfd_boolean find_excl (struct stab_handle *, const char *, bfd_vma);
static bfd_boolean stab_record_variable
static bfd_boolean stab_record_variable
  (void *, struct stab_handle *, const char *, debug_type,
  (void *, struct stab_handle *, const char *, debug_type,
   enum debug_var_kind, bfd_vma);
   enum debug_var_kind, bfd_vma);
static bfd_boolean stab_emit_pending_vars (void *, struct stab_handle *);
static bfd_boolean stab_emit_pending_vars (void *, struct stab_handle *);
static debug_type *stab_find_slot (struct stab_handle *, const int *);
static debug_type *stab_find_slot (struct stab_handle *, const int *);
static debug_type stab_find_type (void *, struct stab_handle *, const int *);
static debug_type stab_find_type (void *, struct stab_handle *, const int *);
static bfd_boolean stab_record_type
static bfd_boolean stab_record_type
  (void *, struct stab_handle *, const int *, debug_type);
  (void *, struct stab_handle *, const int *, debug_type);
static debug_type stab_xcoff_builtin_type
static debug_type stab_xcoff_builtin_type
  (void *, struct stab_handle *, int);
  (void *, struct stab_handle *, int);
static debug_type stab_find_tagged_type
static debug_type stab_find_tagged_type
  (void *, struct stab_handle *, const char *, int, enum debug_type_kind);
  (void *, struct stab_handle *, const char *, int, enum debug_type_kind);
static debug_type *stab_demangle_argtypes
static debug_type *stab_demangle_argtypes
  (void *, struct stab_handle *, const char *, bfd_boolean *, unsigned int);
  (void *, struct stab_handle *, const char *, bfd_boolean *, unsigned int);
static debug_type *stab_demangle_v3_argtypes
static debug_type *stab_demangle_v3_argtypes
  (void *, struct stab_handle *, const char *, bfd_boolean *);
  (void *, struct stab_handle *, const char *, bfd_boolean *);
static debug_type *stab_demangle_v3_arglist
static debug_type *stab_demangle_v3_arglist
  (void *, struct stab_handle *, struct demangle_component *, bfd_boolean *);
  (void *, struct stab_handle *, struct demangle_component *, bfd_boolean *);
static debug_type stab_demangle_v3_arg
static debug_type stab_demangle_v3_arg
  (void *, struct stab_handle *, struct demangle_component *, debug_type,
  (void *, struct stab_handle *, struct demangle_component *, debug_type,
   bfd_boolean *);
   bfd_boolean *);
 
 
/* Save a string in memory.  */
/* Save a string in memory.  */
 
 
static char *
static char *
savestring (const char *start, int len)
savestring (const char *start, int len)
{
{
  char *ret;
  char *ret;
 
 
  ret = (char *) xmalloc (len + 1);
  ret = (char *) xmalloc (len + 1);
  memcpy (ret, start, len);
  memcpy (ret, start, len);
  ret[len] = '\0';
  ret[len] = '\0';
  return ret;
  return ret;
}
}
 
 
/* Read a number from a string.  */
/* Read a number from a string.  */
 
 
static bfd_vma
static bfd_vma
parse_number (const char **pp, bfd_boolean *poverflow)
parse_number (const char **pp, bfd_boolean *poverflow)
{
{
  unsigned long ul;
  unsigned long ul;
  const char *orig;
  const char *orig;
 
 
  if (poverflow != NULL)
  if (poverflow != NULL)
    *poverflow = FALSE;
    *poverflow = FALSE;
 
 
  orig = *pp;
  orig = *pp;
 
 
  errno = 0;
  errno = 0;
  ul = strtoul (*pp, (char **) pp, 0);
  ul = strtoul (*pp, (char **) pp, 0);
  if (ul + 1 != 0 || errno == 0)
  if (ul + 1 != 0 || errno == 0)
    {
    {
      /* If bfd_vma is larger than unsigned long, and the number is
      /* If bfd_vma is larger than unsigned long, and the number is
         meant to be negative, we have to make sure that we sign
         meant to be negative, we have to make sure that we sign
         extend properly.  */
         extend properly.  */
      if (*orig == '-')
      if (*orig == '-')
        return (bfd_vma) (bfd_signed_vma) (long) ul;
        return (bfd_vma) (bfd_signed_vma) (long) ul;
      return (bfd_vma) ul;
      return (bfd_vma) ul;
    }
    }
 
 
  /* Note that even though strtoul overflowed, it should have set *pp
  /* Note that even though strtoul overflowed, it should have set *pp
     to the end of the number, which is where we want it.  */
     to the end of the number, which is where we want it.  */
  if (sizeof (bfd_vma) > sizeof (unsigned long))
  if (sizeof (bfd_vma) > sizeof (unsigned long))
    {
    {
      const char *p;
      const char *p;
      bfd_boolean neg;
      bfd_boolean neg;
      int base;
      int base;
      bfd_vma over, lastdig;
      bfd_vma over, lastdig;
      bfd_boolean overflow;
      bfd_boolean overflow;
      bfd_vma v;
      bfd_vma v;
 
 
      /* Our own version of strtoul, for a bfd_vma.  */
      /* Our own version of strtoul, for a bfd_vma.  */
      p = orig;
      p = orig;
 
 
      neg = FALSE;
      neg = FALSE;
      if (*p == '+')
      if (*p == '+')
        ++p;
        ++p;
      else if (*p == '-')
      else if (*p == '-')
        {
        {
          neg = TRUE;
          neg = TRUE;
          ++p;
          ++p;
        }
        }
 
 
      base = 10;
      base = 10;
      if (*p == '0')
      if (*p == '0')
        {
        {
          if (p[1] == 'x' || p[1] == 'X')
          if (p[1] == 'x' || p[1] == 'X')
            {
            {
              base = 16;
              base = 16;
              p += 2;
              p += 2;
            }
            }
          else
          else
            {
            {
              base = 8;
              base = 8;
              ++p;
              ++p;
            }
            }
        }
        }
 
 
      over = ((bfd_vma) (bfd_signed_vma) -1) / (bfd_vma) base;
      over = ((bfd_vma) (bfd_signed_vma) -1) / (bfd_vma) base;
      lastdig = ((bfd_vma) (bfd_signed_vma) -1) % (bfd_vma) base;
      lastdig = ((bfd_vma) (bfd_signed_vma) -1) % (bfd_vma) base;
 
 
      overflow = FALSE;
      overflow = FALSE;
      v = 0;
      v = 0;
      while (1)
      while (1)
        {
        {
          int d;
          int d;
 
 
          d = *p++;
          d = *p++;
          if (ISDIGIT (d))
          if (ISDIGIT (d))
            d -= '0';
            d -= '0';
          else if (ISUPPER (d))
          else if (ISUPPER (d))
            d -= 'A';
            d -= 'A';
          else if (ISLOWER (d))
          else if (ISLOWER (d))
            d -= 'a';
            d -= 'a';
          else
          else
            break;
            break;
 
 
          if (d >= base)
          if (d >= base)
            break;
            break;
 
 
          if (v > over || (v == over && (bfd_vma) d > lastdig))
          if (v > over || (v == over && (bfd_vma) d > lastdig))
            {
            {
              overflow = TRUE;
              overflow = TRUE;
              break;
              break;
            }
            }
        }
        }
 
 
      if (! overflow)
      if (! overflow)
        {
        {
          if (neg)
          if (neg)
            v = - v;
            v = - v;
          return v;
          return v;
        }
        }
    }
    }
 
 
  /* If we get here, the number is too large to represent in a
  /* If we get here, the number is too large to represent in a
     bfd_vma.  */
     bfd_vma.  */
  if (poverflow != NULL)
  if (poverflow != NULL)
    *poverflow = TRUE;
    *poverflow = TRUE;
  else
  else
    warn_stab (orig, _("numeric overflow"));
    warn_stab (orig, _("numeric overflow"));
 
 
  return 0;
  return 0;
}
}
 
 
/* Give an error for a bad stab string.  */
/* Give an error for a bad stab string.  */
 
 
static void
static void
bad_stab (const char *p)
bad_stab (const char *p)
{
{
  fprintf (stderr, _("Bad stab: %s\n"), p);
  fprintf (stderr, _("Bad stab: %s\n"), p);
}
}
 
 
/* Warn about something in a stab string.  */
/* Warn about something in a stab string.  */
 
 
static void
static void
warn_stab (const char *p, const char *err)
warn_stab (const char *p, const char *err)
{
{
  fprintf (stderr, _("Warning: %s: %s\n"), err, p);
  fprintf (stderr, _("Warning: %s: %s\n"), err, p);
}
}
 
 
/* Create a handle to parse stabs symbols with.  */
/* Create a handle to parse stabs symbols with.  */
 
 
void *
void *
start_stab (void *dhandle ATTRIBUTE_UNUSED, bfd *abfd, bfd_boolean sections,
start_stab (void *dhandle ATTRIBUTE_UNUSED, bfd *abfd, bfd_boolean sections,
            asymbol **syms, long symcount)
            asymbol **syms, long symcount)
{
{
  struct stab_handle *ret;
  struct stab_handle *ret;
 
 
  ret = (struct stab_handle *) xmalloc (sizeof *ret);
  ret = (struct stab_handle *) xmalloc (sizeof *ret);
  memset (ret, 0, sizeof *ret);
  memset (ret, 0, sizeof *ret);
  ret->abfd = abfd;
  ret->abfd = abfd;
  ret->sections = sections;
  ret->sections = sections;
  ret->syms = syms;
  ret->syms = syms;
  ret->symcount = symcount;
  ret->symcount = symcount;
  ret->files = 1;
  ret->files = 1;
  ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types);
  ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types);
  ret->file_types[0] = NULL;
  ret->file_types[0] = NULL;
  ret->function_end = (bfd_vma) -1;
  ret->function_end = (bfd_vma) -1;
  return (void *) ret;
  return (void *) ret;
}
}
 
 
/* When we have processed all the stabs information, we need to go
/* When we have processed all the stabs information, we need to go
   through and fill in all the undefined tags.  */
   through and fill in all the undefined tags.  */
 
 
bfd_boolean
bfd_boolean
finish_stab (void *dhandle, void *handle)
finish_stab (void *dhandle, void *handle)
{
{
  struct stab_handle *info = (struct stab_handle *) handle;
  struct stab_handle *info = (struct stab_handle *) handle;
  struct stab_tag *st;
  struct stab_tag *st;
 
 
  if (info->within_function)
  if (info->within_function)
    {
    {
      if (! stab_emit_pending_vars (dhandle, info)
      if (! stab_emit_pending_vars (dhandle, info)
          || ! debug_end_function (dhandle, info->function_end))
          || ! debug_end_function (dhandle, info->function_end))
        return FALSE;
        return FALSE;
      info->within_function = FALSE;
      info->within_function = FALSE;
      info->function_end = (bfd_vma) -1;
      info->function_end = (bfd_vma) -1;
    }
    }
 
 
  for (st = info->tags; st != NULL; st = st->next)
  for (st = info->tags; st != NULL; st = st->next)
    {
    {
      enum debug_type_kind kind;
      enum debug_type_kind kind;
 
 
      kind = st->kind;
      kind = st->kind;
      if (kind == DEBUG_KIND_ILLEGAL)
      if (kind == DEBUG_KIND_ILLEGAL)
        kind = DEBUG_KIND_STRUCT;
        kind = DEBUG_KIND_STRUCT;
      st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind);
      st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind);
      if (st->slot == DEBUG_TYPE_NULL)
      if (st->slot == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Handle a single stabs symbol.  */
/* Handle a single stabs symbol.  */
 
 
bfd_boolean
bfd_boolean
parse_stab (void *dhandle, void *handle, int type, int desc, bfd_vma value,
parse_stab (void *dhandle, void *handle, int type, int desc, bfd_vma value,
            const char *string)
            const char *string)
{
{
  struct stab_handle *info = (struct stab_handle *) handle;
  struct stab_handle *info = (struct stab_handle *) handle;
 
 
  /* gcc will emit two N_SO strings per compilation unit, one for the
  /* 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
     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
     strings as we see them, and start the new compilation unit when
     we see a non N_SO symbol.  */
     we see a non N_SO symbol.  */
  if (info->so_string != NULL
  if (info->so_string != NULL
      && (type != N_SO || *string == '\0' || value != info->so_value))
      && (type != N_SO || *string == '\0' || value != info->so_value))
    {
    {
      if (! debug_set_filename (dhandle, info->so_string))
      if (! debug_set_filename (dhandle, info->so_string))
        return FALSE;
        return FALSE;
      info->main_filename = info->so_string;
      info->main_filename = info->so_string;
 
 
      info->gcc_compiled = 0;
      info->gcc_compiled = 0;
      info->n_opt_found = FALSE;
      info->n_opt_found = FALSE;
 
 
      /* Generally, for stabs in the symbol table, the N_LBRAC and
      /* Generally, for stabs in the symbol table, the N_LBRAC and
         N_RBRAC symbols are relative to the N_SO symbol value.  */
         N_RBRAC symbols are relative to the N_SO symbol value.  */
      if (! info->sections)
      if (! info->sections)
        info->file_start_offset = info->so_value;
        info->file_start_offset = info->so_value;
 
 
      /* We need to reset the mapping from type numbers to types.  We
      /* We need to reset the mapping from type numbers to types.  We
         can't free the old mapping, because of the use of
         can't free the old mapping, because of the use of
         debug_make_indirect_type.  */
         debug_make_indirect_type.  */
      info->files = 1;
      info->files = 1;
      info->file_types = ((struct stab_types **)
      info->file_types = ((struct stab_types **)
                          xmalloc (sizeof *info->file_types));
                          xmalloc (sizeof *info->file_types));
      info->file_types[0] = NULL;
      info->file_types[0] = NULL;
 
 
      info->so_string = NULL;
      info->so_string = NULL;
 
 
      /* Now process whatever type we just got.  */
      /* Now process whatever type we just got.  */
    }
    }
 
 
  switch (type)
  switch (type)
    {
    {
    case N_FN:
    case N_FN:
    case N_FN_SEQ:
    case N_FN_SEQ:
      break;
      break;
 
 
    case N_LBRAC:
    case N_LBRAC:
      /* Ignore extra outermost context from SunPRO cc and acc.  */
      /* Ignore extra outermost context from SunPRO cc and acc.  */
      if (info->n_opt_found && desc == 1)
      if (info->n_opt_found && desc == 1)
        break;
        break;
 
 
      if (! info->within_function)
      if (! info->within_function)
        {
        {
          fprintf (stderr, _("N_LBRAC not within function\n"));
          fprintf (stderr, _("N_LBRAC not within function\n"));
          return FALSE;
          return FALSE;
        }
        }
 
 
      /* Start an inner lexical block.  */
      /* Start an inner lexical block.  */
      if (! debug_start_block (dhandle,
      if (! debug_start_block (dhandle,
                               (value
                               (value
                                + info->file_start_offset
                                + info->file_start_offset
                                + info->function_start_offset)))
                                + info->function_start_offset)))
        return FALSE;
        return FALSE;
 
 
      /* Emit any pending variable definitions.  */
      /* Emit any pending variable definitions.  */
      if (! stab_emit_pending_vars (dhandle, info))
      if (! stab_emit_pending_vars (dhandle, info))
        return FALSE;
        return FALSE;
 
 
      ++info->block_depth;
      ++info->block_depth;
      break;
      break;
 
 
    case N_RBRAC:
    case N_RBRAC:
      /* Ignore extra outermost context from SunPRO cc and acc.  */
      /* Ignore extra outermost context from SunPRO cc and acc.  */
      if (info->n_opt_found && desc == 1)
      if (info->n_opt_found && desc == 1)
        break;
        break;
 
 
      /* We shouldn't have any pending variable definitions here, but,
      /* We shouldn't have any pending variable definitions here, but,
         if we do, we probably need to emit them before closing the
         if we do, we probably need to emit them before closing the
         block.  */
         block.  */
      if (! stab_emit_pending_vars (dhandle, info))
      if (! stab_emit_pending_vars (dhandle, info))
        return FALSE;
        return FALSE;
 
 
      /* End an inner lexical block.  */
      /* End an inner lexical block.  */
      if (! debug_end_block (dhandle,
      if (! debug_end_block (dhandle,
                             (value
                             (value
                              + info->file_start_offset
                              + info->file_start_offset
                              + info->function_start_offset)))
                              + info->function_start_offset)))
        return FALSE;
        return FALSE;
 
 
      --info->block_depth;
      --info->block_depth;
      if (info->block_depth < 0)
      if (info->block_depth < 0)
        {
        {
          fprintf (stderr, _("Too many N_RBRACs\n"));
          fprintf (stderr, _("Too many N_RBRACs\n"));
          return FALSE;
          return FALSE;
        }
        }
      break;
      break;
 
 
    case N_SO:
    case N_SO:
      /* This always ends a function.  */
      /* This always ends a function.  */
      if (info->within_function)
      if (info->within_function)
        {
        {
          bfd_vma endval;
          bfd_vma endval;
 
 
          endval = value;
          endval = value;
          if (*string != '\0'
          if (*string != '\0'
              && info->function_end != (bfd_vma) -1
              && info->function_end != (bfd_vma) -1
              && info->function_end < endval)
              && info->function_end < endval)
            endval = info->function_end;
            endval = info->function_end;
          if (! stab_emit_pending_vars (dhandle, info)
          if (! stab_emit_pending_vars (dhandle, info)
              || ! debug_end_function (dhandle, endval))
              || ! debug_end_function (dhandle, endval))
            return FALSE;
            return FALSE;
          info->within_function = FALSE;
          info->within_function = FALSE;
          info->function_end = (bfd_vma) -1;
          info->function_end = (bfd_vma) -1;
        }
        }
 
 
      /* An empty string is emitted by gcc at the end of a compilation
      /* An empty string is emitted by gcc at the end of a compilation
         unit.  */
         unit.  */
      if (*string == '\0')
      if (*string == '\0')
        return TRUE;
        return TRUE;
 
 
      /* Just accumulate strings until we see a non N_SO symbol.  If
      /* Just accumulate strings until we see a non N_SO symbol.  If
         the string starts with a directory separator or some other
         the string starts with a directory separator or some other
         form of absolute path specification, we discard the previously
         form of absolute path specification, we discard the previously
         accumulated strings.  */
         accumulated strings.  */
      if (info->so_string == NULL)
      if (info->so_string == NULL)
        info->so_string = xstrdup (string);
        info->so_string = xstrdup (string);
      else
      else
        {
        {
          char *f;
          char *f;
 
 
          f = info->so_string;
          f = info->so_string;
 
 
          if (IS_ABSOLUTE_PATH (string))
          if (IS_ABSOLUTE_PATH (string))
            info->so_string = xstrdup (string);
            info->so_string = xstrdup (string);
          else
          else
            info->so_string = concat (info->so_string, string,
            info->so_string = concat (info->so_string, string,
                                      (const char *) NULL);
                                      (const char *) NULL);
          free (f);
          free (f);
        }
        }
 
 
      info->so_value = value;
      info->so_value = value;
 
 
      break;
      break;
 
 
    case N_SOL:
    case N_SOL:
      /* Start an include file.  */
      /* Start an include file.  */
      if (! debug_start_source (dhandle, string))
      if (! debug_start_source (dhandle, string))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case N_BINCL:
    case N_BINCL:
      /* Start an include file which may be replaced.  */
      /* Start an include file which may be replaced.  */
      push_bincl (info, string, value);
      push_bincl (info, string, value);
      if (! debug_start_source (dhandle, string))
      if (! debug_start_source (dhandle, string))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case N_EINCL:
    case N_EINCL:
      /* End an N_BINCL include.  */
      /* End an N_BINCL include.  */
      if (! debug_start_source (dhandle, pop_bincl (info)))
      if (! debug_start_source (dhandle, pop_bincl (info)))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case N_EXCL:
    case N_EXCL:
      /* This is a duplicate of a header file named by N_BINCL which
      /* This is a duplicate of a header file named by N_BINCL which
         was eliminated by the linker.  */
         was eliminated by the linker.  */
      if (! find_excl (info, string, value))
      if (! find_excl (info, string, value))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case N_SLINE:
    case N_SLINE:
      if (! debug_record_line (dhandle, desc,
      if (! debug_record_line (dhandle, desc,
                               value + (info->within_function
                               value + (info->within_function
                                        ? info->function_start_offset : 0)))
                                        ? info->function_start_offset : 0)))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case N_BCOMM:
    case N_BCOMM:
      if (! debug_start_common_block (dhandle, string))
      if (! debug_start_common_block (dhandle, string))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case N_ECOMM:
    case N_ECOMM:
      if (! debug_end_common_block (dhandle, string))
      if (! debug_end_common_block (dhandle, string))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case N_FUN:
    case N_FUN:
      if (*string == '\0')
      if (*string == '\0')
        {
        {
          if (info->within_function)
          if (info->within_function)
            {
            {
              /* This always marks the end of a function; we don't
              /* This always marks the end of a function; we don't
                 need to worry about info->function_end.  */
                 need to worry about info->function_end.  */
              if (info->sections)
              if (info->sections)
                value += info->function_start_offset;
                value += info->function_start_offset;
              if (! stab_emit_pending_vars (dhandle, info)
              if (! stab_emit_pending_vars (dhandle, info)
                  || ! debug_end_function (dhandle, value))
                  || ! debug_end_function (dhandle, value))
                return FALSE;
                return FALSE;
              info->within_function = FALSE;
              info->within_function = FALSE;
              info->function_end = (bfd_vma) -1;
              info->function_end = (bfd_vma) -1;
            }
            }
          break;
          break;
        }
        }
 
 
      /* A const static symbol in the .text section will have an N_FUN
      /* 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,
         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
         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
         always emit an empty N_FUN.  We can't call debug_end_function
         here, because it might be a local static symbol.  */
         here, because it might be a local static symbol.  */
      if (info->within_function
      if (info->within_function
          && (info->function_end == (bfd_vma) -1
          && (info->function_end == (bfd_vma) -1
              || value < info->function_end))
              || value < info->function_end))
        info->function_end = value;
        info->function_end = value;
 
 
      /* Fall through.  */
      /* Fall through.  */
      /* FIXME: gdb checks the string for N_STSYM, N_LCSYM or N_ROSYM
      /* 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
         symbols, and if it does not start with :S, gdb relocates the
         value to the start of the section.  gcc always seems to use
         value to the start of the section.  gcc always seems to use
         :S, so we don't worry about this.  */
         :S, so we don't worry about this.  */
      /* Fall through.  */
      /* Fall through.  */
    default:
    default:
      {
      {
        const char *colon;
        const char *colon;
 
 
        colon = strchr (string, ':');
        colon = strchr (string, ':');
        if (colon != NULL
        if (colon != NULL
            && (colon[1] == 'f' || colon[1] == 'F'))
            && (colon[1] == 'f' || colon[1] == 'F'))
          {
          {
            if (info->within_function)
            if (info->within_function)
              {
              {
                bfd_vma endval;
                bfd_vma endval;
 
 
                endval = value;
                endval = value;
                if (info->function_end != (bfd_vma) -1
                if (info->function_end != (bfd_vma) -1
                    && info->function_end < endval)
                    && info->function_end < endval)
                  endval = info->function_end;
                  endval = info->function_end;
                if (! stab_emit_pending_vars (dhandle, info)
                if (! stab_emit_pending_vars (dhandle, info)
                    || ! debug_end_function (dhandle, endval))
                    || ! debug_end_function (dhandle, endval))
                  return FALSE;
                  return FALSE;
                info->function_end = (bfd_vma) -1;
                info->function_end = (bfd_vma) -1;
              }
              }
            /* For stabs in sections, line numbers and block addresses
            /* For stabs in sections, line numbers and block addresses
               are offsets from the start of the function.  */
               are offsets from the start of the function.  */
            if (info->sections)
            if (info->sections)
              info->function_start_offset = value;
              info->function_start_offset = value;
            info->within_function = TRUE;
            info->within_function = TRUE;
          }
          }
 
 
        if (! parse_stab_string (dhandle, info, type, desc, value, string))
        if (! parse_stab_string (dhandle, info, type, desc, value, string))
          return FALSE;
          return FALSE;
      }
      }
      break;
      break;
 
 
    case N_OPT:
    case N_OPT:
      if (string != NULL && strcmp (string, "gcc2_compiled.") == 0)
      if (string != NULL && strcmp (string, "gcc2_compiled.") == 0)
        info->gcc_compiled = 2;
        info->gcc_compiled = 2;
      else if (string != NULL && strcmp (string, "gcc_compiled.") == 0)
      else if (string != NULL && strcmp (string, "gcc_compiled.") == 0)
        info->gcc_compiled = 1;
        info->gcc_compiled = 1;
      else
      else
        info->n_opt_found = TRUE;
        info->n_opt_found = TRUE;
      break;
      break;
 
 
    case N_OBJ:
    case N_OBJ:
    case N_ENDM:
    case N_ENDM:
    case N_MAIN:
    case N_MAIN:
    case N_WARNING:
    case N_WARNING:
      break;
      break;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Parse the stabs string.  */
/* Parse the stabs string.  */
 
 
static bfd_boolean
static bfd_boolean
parse_stab_string (void *dhandle, struct stab_handle *info, int stabtype,
parse_stab_string (void *dhandle, struct stab_handle *info, int stabtype,
                   int desc ATTRIBUTE_UNUSED, bfd_vma value, const char *string)
                   int desc ATTRIBUTE_UNUSED, bfd_vma value, const char *string)
{
{
  const char *p;
  const char *p;
  char *name;
  char *name;
  int type;
  int type;
  debug_type dtype;
  debug_type dtype;
  bfd_boolean synonym;
  bfd_boolean synonym;
  bfd_boolean self_crossref;
  bfd_boolean self_crossref;
  debug_type *slot;
  debug_type *slot;
 
 
  p = strchr (string, ':');
  p = strchr (string, ':');
  if (p == NULL)
  if (p == NULL)
    return TRUE;
    return TRUE;
 
 
  while (p[1] == ':')
  while (p[1] == ':')
    {
    {
      p += 2;
      p += 2;
      p = strchr (p, ':');
      p = strchr (p, ':');
      if (p == NULL)
      if (p == NULL)
        {
        {
          bad_stab (string);
          bad_stab (string);
          return FALSE;
          return FALSE;
        }
        }
    }
    }
 
 
  /* FIXME: Sometimes the special C++ names start with '.'.  */
  /* FIXME: Sometimes the special C++ names start with '.'.  */
  name = NULL;
  name = NULL;
  if (string[0] == '$')
  if (string[0] == '$')
    {
    {
      switch (string[1])
      switch (string[1])
        {
        {
        case 't':
        case 't':
          name = "this";
          name = "this";
          break;
          break;
        case 'v':
        case 'v':
          /* Was: name = "vptr"; */
          /* Was: name = "vptr"; */
          break;
          break;
        case 'e':
        case 'e':
          name = "eh_throw";
          name = "eh_throw";
          break;
          break;
        case '_':
        case '_':
          /* This was an anonymous type that was never fixed up.  */
          /* This was an anonymous type that was never fixed up.  */
          break;
          break;
        case 'X':
        case 'X':
          /* SunPRO (3.0 at least) static variable encoding.  */
          /* SunPRO (3.0 at least) static variable encoding.  */
          break;
          break;
        default:
        default:
          warn_stab (string, _("unknown C++ encoded name"));
          warn_stab (string, _("unknown C++ encoded name"));
          break;
          break;
        }
        }
    }
    }
 
 
  if (name == NULL)
  if (name == NULL)
    {
    {
      if (p == string || (string[0] == ' ' && p == string + 1))
      if (p == string || (string[0] == ' ' && p == string + 1))
        name = NULL;
        name = NULL;
      else
      else
        name = savestring (string, p - string);
        name = savestring (string, p - string);
    }
    }
 
 
  ++p;
  ++p;
  if (ISDIGIT (*p) || *p == '(' || *p == '-')
  if (ISDIGIT (*p) || *p == '(' || *p == '-')
    type = 'l';
    type = 'l';
  else
  else
    type = *p++;
    type = *p++;
 
 
  switch (type)
  switch (type)
    {
    {
    case 'c':
    case 'c':
      /* c is a special case, not followed by a type-number.
      /* c is a special case, not followed by a type-number.
         SYMBOL:c=iVALUE for an integer constant symbol.
         SYMBOL:c=iVALUE for an integer constant symbol.
         SYMBOL:c=rVALUE for a floating constant symbol.
         SYMBOL:c=rVALUE for a floating constant symbol.
         SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
         SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol.
         e.g. "b:c=e6,0" for "const b = blob1"
         e.g. "b:c=e6,0" for "const b = blob1"
         (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;").  */
         (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;").  */
      if (*p != '=')
      if (*p != '=')
        {
        {
          bad_stab (string);
          bad_stab (string);
          return FALSE;
          return FALSE;
        }
        }
      ++p;
      ++p;
      switch (*p++)
      switch (*p++)
        {
        {
        case 'r':
        case 'r':
          /* Floating point constant.  */
          /* Floating point constant.  */
          if (! debug_record_float_const (dhandle, name, atof (p)))
          if (! debug_record_float_const (dhandle, name, atof (p)))
            return FALSE;
            return FALSE;
          break;
          break;
        case 'i':
        case 'i':
          /* Integer constant.  */
          /* Integer constant.  */
          /* Defining integer constants this way is kind of silly,
          /* Defining integer constants this way is kind of silly,
             since 'e' constants allows the compiler to give not only
             since 'e' constants allows the compiler to give not only
             the value, but the type as well.  C has at least int,
             the value, but the type as well.  C has at least int,
             long, unsigned int, and long long as constant types;
             long, unsigned int, and long long as constant types;
             other languages probably should have at least unsigned as
             other languages probably should have at least unsigned as
             well as signed constants.  */
             well as signed constants.  */
          if (! debug_record_int_const (dhandle, name, atoi (p)))
          if (! debug_record_int_const (dhandle, name, atoi (p)))
            return FALSE;
            return FALSE;
          break;
          break;
        case 'e':
        case 'e':
          /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value
          /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value
             can be represented as integral.
             can be represented as integral.
             e.g. "b:c=e6,0" for "const b = blob1"
             e.g. "b:c=e6,0" for "const b = blob1"
             (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;").  */
             (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;").  */
          dtype = parse_stab_type (dhandle, info, (const char *) NULL,
          dtype = parse_stab_type (dhandle, info, (const char *) NULL,
                                   &p, (debug_type **) NULL);
                                   &p, (debug_type **) NULL);
          if (dtype == DEBUG_TYPE_NULL)
          if (dtype == DEBUG_TYPE_NULL)
            return FALSE;
            return FALSE;
          if (*p != ',')
          if (*p != ',')
            {
            {
              bad_stab (string);
              bad_stab (string);
              return FALSE;
              return FALSE;
            }
            }
          if (! debug_record_typed_const (dhandle, name, dtype, atoi (p)))
          if (! debug_record_typed_const (dhandle, name, dtype, atoi (p)))
            return FALSE;
            return FALSE;
          break;
          break;
        default:
        default:
          bad_stab (string);
          bad_stab (string);
          return FALSE;
          return FALSE;
        }
        }
 
 
      break;
      break;
 
 
    case 'C':
    case 'C':
      /* The name of a caught exception.  */
      /* The name of a caught exception.  */
      dtype = parse_stab_type (dhandle, info, (const char *) NULL,
      dtype = parse_stab_type (dhandle, info, (const char *) NULL,
                               &p, (debug_type **) NULL);
                               &p, (debug_type **) NULL);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (! debug_record_label (dhandle, name, dtype, value))
      if (! debug_record_label (dhandle, name, dtype, value))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case 'f':
    case 'f':
    case 'F':
    case 'F':
      /* A function definition.  */
      /* A function definition.  */
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                               (debug_type **) NULL);
                               (debug_type **) NULL);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (! debug_record_function (dhandle, name, dtype, type == 'F', value))
      if (! debug_record_function (dhandle, name, dtype, type == 'F', value))
        return FALSE;
        return FALSE;
 
 
      /* Sun acc puts declared types of arguments here.  We don't care
      /* Sun acc puts declared types of arguments here.  We don't care
         about their actual types (FIXME -- we should remember the whole
         about their actual types (FIXME -- we should remember the whole
         function prototype), but the list may define some new types
         function prototype), but the list may define some new types
         that we have to remember, so we must scan it now.  */
         that we have to remember, so we must scan it now.  */
      while (*p == ';')
      while (*p == ';')
        {
        {
          ++p;
          ++p;
          if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
          if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
                               (debug_type **) NULL)
                               (debug_type **) NULL)
              == DEBUG_TYPE_NULL)
              == DEBUG_TYPE_NULL)
            return FALSE;
            return FALSE;
        }
        }
 
 
      break;
      break;
 
 
    case 'G':
    case 'G':
      {
      {
        char leading;
        char leading;
        long c;
        long c;
        asymbol **ps;
        asymbol **ps;
 
 
        /* A global symbol.  The value must be extracted from the
        /* A global symbol.  The value must be extracted from the
           symbol table.  */
           symbol table.  */
        dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
        dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                                 (debug_type **) NULL);
                                 (debug_type **) NULL);
        if (dtype == DEBUG_TYPE_NULL)
        if (dtype == DEBUG_TYPE_NULL)
          return FALSE;
          return FALSE;
        leading = bfd_get_symbol_leading_char (info->abfd);
        leading = bfd_get_symbol_leading_char (info->abfd);
        for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
        for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
          {
          {
            const char *n;
            const char *n;
 
 
            n = bfd_asymbol_name (*ps);
            n = bfd_asymbol_name (*ps);
            if (leading != '\0' && *n == leading)
            if (leading != '\0' && *n == leading)
              ++n;
              ++n;
            if (*n == *name && strcmp (n, name) == 0)
            if (*n == *name && strcmp (n, name) == 0)
              break;
              break;
          }
          }
        if (c > 0)
        if (c > 0)
          value = bfd_asymbol_value (*ps);
          value = bfd_asymbol_value (*ps);
        if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
        if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
                                    value))
                                    value))
          return FALSE;
          return FALSE;
      }
      }
      break;
      break;
 
 
      /* This case is faked by a conditional above, when there is no
      /* This case is faked by a conditional above, when there is no
         code letter in the dbx data.  Dbx data never actually
         code letter in the dbx data.  Dbx data never actually
         contains 'l'.  */
         contains 'l'.  */
    case 'l':
    case 'l':
    case 's':
    case 's':
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                               (debug_type **) NULL);
                               (debug_type **) NULL);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
      if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
                                  value))
                                  value))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case 'p':
    case 'p':
      /* A function parameter.  */
      /* A function parameter.  */
      if (*p != 'F')
      if (*p != 'F')
        dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
        dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                                 (debug_type **) NULL);
                                 (debug_type **) NULL);
      else
      else
        {
        {
        /* pF is a two-letter code that means a function parameter in
        /* pF is a two-letter code that means a function parameter in
           Fortran.  The type-number specifies the type of the return
           Fortran.  The type-number specifies the type of the return
           value.  Translate it into a pointer-to-function type.  */
           value.  Translate it into a pointer-to-function type.  */
          ++p;
          ++p;
          dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
          dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                                   (debug_type **) NULL);
                                   (debug_type **) NULL);
          if (dtype != DEBUG_TYPE_NULL)
          if (dtype != DEBUG_TYPE_NULL)
            {
            {
              debug_type ftype;
              debug_type ftype;
 
 
              ftype = debug_make_function_type (dhandle, dtype,
              ftype = debug_make_function_type (dhandle, dtype,
                                                (debug_type *) NULL, FALSE);
                                                (debug_type *) NULL, FALSE);
              dtype = debug_make_pointer_type (dhandle, ftype);
              dtype = debug_make_pointer_type (dhandle, ftype);
            }
            }
        }
        }
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_STACK,
      if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_STACK,
                                    value))
                                    value))
        return FALSE;
        return FALSE;
 
 
      /* FIXME: At this point gdb considers rearranging the parameter
      /* FIXME: At this point gdb considers rearranging the parameter
         address on a big endian machine if it is smaller than an int.
         address on a big endian machine if it is smaller than an int.
         We have no way to do that, since we don't really know much
         We have no way to do that, since we don't really know much
         about the target.  */
         about the target.  */
      break;
      break;
 
 
    case 'P':
    case 'P':
      if (stabtype == N_FUN)
      if (stabtype == N_FUN)
        {
        {
          /* Prototype of a function referenced by this file.  */
          /* Prototype of a function referenced by this file.  */
          while (*p == ';')
          while (*p == ';')
            {
            {
              ++p;
              ++p;
              if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
              if (parse_stab_type (dhandle, info, (const char *) NULL, &p,
                                   (debug_type **) NULL)
                                   (debug_type **) NULL)
                  == DEBUG_TYPE_NULL)
                  == DEBUG_TYPE_NULL)
                return FALSE;
                return FALSE;
            }
            }
          break;
          break;
        }
        }
      /* Fall through.  */
      /* Fall through.  */
    case 'R':
    case 'R':
      /* Parameter which is in a register.  */
      /* Parameter which is in a register.  */
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                               (debug_type **) NULL);
                               (debug_type **) NULL);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG,
      if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG,
                                    value))
                                    value))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case 'r':
    case 'r':
      /* Register variable (either global or local).  */
      /* Register variable (either global or local).  */
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                               (debug_type **) NULL);
                               (debug_type **) NULL);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER,
      if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER,
                                  value))
                                  value))
        return FALSE;
        return FALSE;
 
 
      /* FIXME: At this point gdb checks to combine pairs of 'p' and
      /* FIXME: At this point gdb checks to combine pairs of 'p' and
         'r' stabs into a single 'P' stab.  */
         'r' stabs into a single 'P' stab.  */
      break;
      break;
 
 
    case 'S':
    case 'S':
      /* Static symbol at top level of file.  */
      /* Static symbol at top level of file.  */
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                               (debug_type **) NULL);
                               (debug_type **) NULL);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC,
      if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC,
                                  value))
                                  value))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case 't':
    case 't':
      /* A typedef.  */
      /* A typedef.  */
      dtype = parse_stab_type (dhandle, info, name, &p, &slot);
      dtype = parse_stab_type (dhandle, info, name, &p, &slot);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (name == NULL)
      if (name == NULL)
        {
        {
          /* A nameless type.  Nothing to do.  */
          /* A nameless type.  Nothing to do.  */
          return TRUE;
          return TRUE;
        }
        }
 
 
      dtype = debug_name_type (dhandle, name, dtype);
      dtype = debug_name_type (dhandle, name, dtype);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
 
 
      if (slot != NULL)
      if (slot != NULL)
        *slot = dtype;
        *slot = dtype;
 
 
      break;
      break;
 
 
    case 'T':
    case 'T':
      /* Struct, union, or enum tag.  For GNU C++, this can be be followed
      /* Struct, union, or enum tag.  For GNU C++, this can be be followed
         by 't' which means we are typedef'ing it as well.  */
         by 't' which means we are typedef'ing it as well.  */
      if (*p != 't')
      if (*p != 't')
        {
        {
          synonym = FALSE;
          synonym = FALSE;
          /* FIXME: gdb sets synonym to TRUE if the current language
          /* FIXME: gdb sets synonym to TRUE if the current language
             is C++.  */
             is C++.  */
        }
        }
      else
      else
        {
        {
          synonym = TRUE;
          synonym = TRUE;
          ++p;
          ++p;
        }
        }
 
 
      dtype = parse_stab_type (dhandle, info, name, &p, &slot);
      dtype = parse_stab_type (dhandle, info, name, &p, &slot);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (name == NULL)
      if (name == NULL)
        return TRUE;
        return TRUE;
 
 
      /* INFO->SELF_CROSSREF is set by parse_stab_type if this type is
      /* INFO->SELF_CROSSREF is set by parse_stab_type if this type is
         a cross reference to itself.  These are generated by some
         a cross reference to itself.  These are generated by some
         versions of g++.  */
         versions of g++.  */
      self_crossref = info->self_crossref;
      self_crossref = info->self_crossref;
 
 
      dtype = debug_tag_type (dhandle, name, dtype);
      dtype = debug_tag_type (dhandle, name, dtype);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (slot != NULL)
      if (slot != NULL)
        *slot = dtype;
        *slot = dtype;
 
 
      /* See if we have a cross reference to this tag which we can now
      /* See if we have a cross reference to this tag which we can now
         fill in.  Avoid filling in a cross reference to ourselves,
         fill in.  Avoid filling in a cross reference to ourselves,
         because that would lead to circular debugging information.  */
         because that would lead to circular debugging information.  */
      if (! self_crossref)
      if (! self_crossref)
        {
        {
          register struct stab_tag **pst;
          register struct stab_tag **pst;
 
 
          for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next)
          for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next)
            {
            {
              if ((*pst)->name[0] == name[0]
              if ((*pst)->name[0] == name[0]
                  && strcmp ((*pst)->name, name) == 0)
                  && strcmp ((*pst)->name, name) == 0)
                {
                {
                  (*pst)->slot = dtype;
                  (*pst)->slot = dtype;
                  *pst = (*pst)->next;
                  *pst = (*pst)->next;
                  break;
                  break;
                }
                }
            }
            }
        }
        }
 
 
      if (synonym)
      if (synonym)
        {
        {
          dtype = debug_name_type (dhandle, name, dtype);
          dtype = debug_name_type (dhandle, name, dtype);
          if (dtype == DEBUG_TYPE_NULL)
          if (dtype == DEBUG_TYPE_NULL)
            return FALSE;
            return FALSE;
 
 
          if (slot != NULL)
          if (slot != NULL)
            *slot = dtype;
            *slot = dtype;
        }
        }
 
 
      break;
      break;
 
 
    case 'V':
    case 'V':
      /* Static symbol of local scope */
      /* Static symbol of local scope */
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                               (debug_type **) NULL);
                               (debug_type **) NULL);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      /* FIXME: gdb checks os9k_stabs here.  */
      /* FIXME: gdb checks os9k_stabs here.  */
      if (! stab_record_variable (dhandle, info, name, dtype,
      if (! stab_record_variable (dhandle, info, name, dtype,
                                  DEBUG_LOCAL_STATIC, value))
                                  DEBUG_LOCAL_STATIC, value))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case 'v':
    case 'v':
      /* Reference parameter.  */
      /* Reference parameter.  */
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                               (debug_type **) NULL);
                               (debug_type **) NULL);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE,
      if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE,
                                    value))
                                    value))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case 'a':
    case 'a':
      /* Reference parameter which is in a register.  */
      /* Reference parameter which is in a register.  */
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                               (debug_type **) NULL);
                               (debug_type **) NULL);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG,
      if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG,
                                    value))
                                    value))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case 'X':
    case 'X':
      /* This is used by Sun FORTRAN for "function result value".
      /* This is used by Sun FORTRAN for "function result value".
         Sun claims ("dbx and dbxtool interfaces", 2nd ed)
         Sun claims ("dbx and dbxtool interfaces", 2nd ed)
         that Pascal uses it too, but when I tried it Pascal used
         that Pascal uses it too, but when I tried it Pascal used
         "x:3" (local symbol) instead.  */
         "x:3" (local symbol) instead.  */
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
      dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
                               (debug_type **) NULL);
                               (debug_type **) NULL);
      if (dtype == DEBUG_TYPE_NULL)
      if (dtype == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
      if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
      if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
                                  value))
                                  value))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case 'Y':
    case 'Y':
      /* SUNPro C++ Namespace =Yn0.  */
      /* SUNPro C++ Namespace =Yn0.  */
      /* Skip the namespace mapping, as it is not used now.  */
      /* Skip the namespace mapping, as it is not used now.  */
      if (*(++p) == 'n' && *(++p) == '0')
      if (*(++p) == 'n' && *(++p) == '0')
        {
        {
          /* =Yn0name; */
          /* =Yn0name; */
          while (*p != ';')
          while (*p != ';')
            ++p;
            ++p;
          ++p;
          ++p;
          return TRUE;
          return TRUE;
        }
        }
      /* TODO SUNPro C++ support:
      /* TODO SUNPro C++ support:
         Support default arguments after F,P parameters
         Support default arguments after F,P parameters
         Ya = Anonymous unions
         Ya = Anonymous unions
         YM,YD = Pointers to class members
         YM,YD = Pointers to class members
         YT,YI = Templates
         YT,YI = Templates
         YR = Run-time type information (RTTI)  */
         YR = Run-time type information (RTTI)  */
 
 
      /* Fall through.  */
      /* Fall through.  */
 
 
    default:
    default:
      bad_stab (string);
      bad_stab (string);
      return FALSE;
      return FALSE;
    }
    }
 
 
  /* FIXME: gdb converts structure values to structure pointers in a
  /* FIXME: gdb converts structure values to structure pointers in a
     couple of cases, depending upon the target.  */
     couple of cases, depending upon the target.  */
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Parse a stabs type.  The typename argument is non-NULL if this is a
/* 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
   typedef or a tag definition.  The pp argument points to the stab
   string, and is updated.  The slotp argument points to a place to
   string, and is updated.  The slotp argument points to a place to
   store the slot used if the type is being defined.  */
   store the slot used if the type is being defined.  */
 
 
static debug_type
static debug_type
parse_stab_type (void *dhandle, struct stab_handle *info, const char *type_name, const char **pp, debug_type **slotp)
parse_stab_type (void *dhandle, struct stab_handle *info, const char *type_name, const char **pp, debug_type **slotp)
{
{
  const char *orig;
  const char *orig;
  int typenums[2];
  int typenums[2];
  int size;
  int size;
  bfd_boolean stringp;
  bfd_boolean stringp;
  int descriptor;
  int descriptor;
  debug_type dtype;
  debug_type dtype;
 
 
  if (slotp != NULL)
  if (slotp != NULL)
    *slotp = NULL;
    *slotp = NULL;
 
 
  orig = *pp;
  orig = *pp;
 
 
  size = -1;
  size = -1;
  stringp = FALSE;
  stringp = FALSE;
 
 
  info->self_crossref = FALSE;
  info->self_crossref = FALSE;
 
 
  /* Read type number if present.  The type number may be omitted.
  /* Read type number if present.  The type number may be omitted.
     for instance in a two-dimensional array declared with type
     for instance in a two-dimensional array declared with type
     "ar1;1;10;ar1;1;10;4".  */
     "ar1;1;10;ar1;1;10;4".  */
  if (! ISDIGIT (**pp) && **pp != '(' && **pp != '-')
  if (! ISDIGIT (**pp) && **pp != '(' && **pp != '-')
    {
    {
      /* 'typenums=' not present, type is anonymous.  Read and return
      /* 'typenums=' not present, type is anonymous.  Read and return
         the definition, but don't put it in the type vector.  */
         the definition, but don't put it in the type vector.  */
      typenums[0] = typenums[1] = -1;
      typenums[0] = typenums[1] = -1;
    }
    }
  else
  else
    {
    {
      if (! parse_stab_type_number (pp, typenums))
      if (! parse_stab_type_number (pp, typenums))
        return DEBUG_TYPE_NULL;
        return DEBUG_TYPE_NULL;
 
 
      if (**pp != '=')
      if (**pp != '=')
        /* Type is not being defined here.  Either it already
        /* Type is not being defined here.  Either it already
           exists, or this is a forward reference to it.  */
           exists, or this is a forward reference to it.  */
        return stab_find_type (dhandle, info, typenums);
        return stab_find_type (dhandle, info, typenums);
 
 
      /* Only set the slot if the type is being defined.  This means
      /* Only set the slot if the type is being defined.  This means
         that the mapping from type numbers to types will only record
         that the mapping from type numbers to types will only record
         the name of the typedef which defines a type.  If we don't do
         the name of the typedef which defines a type.  If we don't do
         this, then something like
         this, then something like
             typedef int foo;
             typedef int foo;
             int i;
             int i;
         will record that i is of type foo.  Unfortunately, stabs
         will record that i is of type foo.  Unfortunately, stabs
         information is ambiguous about variable types.  For this code,
         information is ambiguous about variable types.  For this code,
             typedef int foo;
             typedef int foo;
             int i;
             int i;
             foo j;
             foo j;
         the stabs information records both i and j as having the same
         the stabs information records both i and j as having the same
         type.  This could be fixed by patching the compiler.  */
         type.  This could be fixed by patching the compiler.  */
      if (slotp != NULL && typenums[0] >= 0 && typenums[1] >= 0)
      if (slotp != NULL && typenums[0] >= 0 && typenums[1] >= 0)
        *slotp = stab_find_slot (info, typenums);
        *slotp = stab_find_slot (info, typenums);
 
 
      /* Type is being defined here.  */
      /* Type is being defined here.  */
      /* Skip the '='.  */
      /* Skip the '='.  */
      ++*pp;
      ++*pp;
 
 
      while (**pp == '@')
      while (**pp == '@')
        {
        {
          const char *p = *pp + 1;
          const char *p = *pp + 1;
          const char *attr;
          const char *attr;
 
 
          if (ISDIGIT (*p) || *p == '(' || *p == '-')
          if (ISDIGIT (*p) || *p == '(' || *p == '-')
            /* Member type.  */
            /* Member type.  */
            break;
            break;
 
 
          /* Type attributes.  */
          /* Type attributes.  */
          attr = p;
          attr = p;
 
 
          for (; *p != ';'; ++p)
          for (; *p != ';'; ++p)
            {
            {
              if (*p == '\0')
              if (*p == '\0')
                {
                {
                  bad_stab (orig);
                  bad_stab (orig);
                  return DEBUG_TYPE_NULL;
                  return DEBUG_TYPE_NULL;
                }
                }
            }
            }
          *pp = p + 1;
          *pp = p + 1;
 
 
          switch (*attr)
          switch (*attr)
            {
            {
            case 's':
            case 's':
              size = atoi (attr + 1);
              size = atoi (attr + 1);
              size /= 8;  /* Size is in bits.  We store it in bytes.  */
              size /= 8;  /* Size is in bits.  We store it in bytes.  */
              if (size <= 0)
              if (size <= 0)
                size = -1;
                size = -1;
              break;
              break;
 
 
            case 'S':
            case 'S':
              stringp = TRUE;
              stringp = TRUE;
              break;
              break;
 
 
            default:
            default:
              /* Ignore unrecognized type attributes, so future
              /* Ignore unrecognized type attributes, so future
                 compilers can invent new ones.  */
                 compilers can invent new ones.  */
              break;
              break;
            }
            }
        }
        }
    }
    }
 
 
  descriptor = **pp;
  descriptor = **pp;
  ++*pp;
  ++*pp;
 
 
  switch (descriptor)
  switch (descriptor)
    {
    {
    case 'x':
    case 'x':
      {
      {
        enum debug_type_kind code;
        enum debug_type_kind code;
        const char *q1, *q2, *p;
        const char *q1, *q2, *p;
 
 
        /* A cross reference to another type.  */
        /* A cross reference to another type.  */
        switch (**pp)
        switch (**pp)
          {
          {
          case 's':
          case 's':
            code = DEBUG_KIND_STRUCT;
            code = DEBUG_KIND_STRUCT;
            break;
            break;
          case 'u':
          case 'u':
            code = DEBUG_KIND_UNION;
            code = DEBUG_KIND_UNION;
            break;
            break;
          case 'e':
          case 'e':
            code = DEBUG_KIND_ENUM;
            code = DEBUG_KIND_ENUM;
            break;
            break;
          default:
          default:
            /* Complain and keep going, so compilers can invent new
            /* Complain and keep going, so compilers can invent new
               cross-reference types.  */
               cross-reference types.  */
            warn_stab (orig, _("unrecognized cross reference type"));
            warn_stab (orig, _("unrecognized cross reference type"));
            code = DEBUG_KIND_STRUCT;
            code = DEBUG_KIND_STRUCT;
            break;
            break;
          }
          }
        ++*pp;
        ++*pp;
 
 
        q1 = strchr (*pp, '<');
        q1 = strchr (*pp, '<');
        p = strchr (*pp, ':');
        p = strchr (*pp, ':');
        if (p == NULL)
        if (p == NULL)
          {
          {
            bad_stab (orig);
            bad_stab (orig);
            return DEBUG_TYPE_NULL;
            return DEBUG_TYPE_NULL;
          }
          }
        if (q1 != NULL && p > q1 && p[1] == ':')
        if (q1 != NULL && p > q1 && p[1] == ':')
          {
          {
            int nest = 0;
            int nest = 0;
 
 
            for (q2 = q1; *q2 != '\0'; ++q2)
            for (q2 = q1; *q2 != '\0'; ++q2)
              {
              {
                if (*q2 == '<')
                if (*q2 == '<')
                  ++nest;
                  ++nest;
                else if (*q2 == '>')
                else if (*q2 == '>')
                  --nest;
                  --nest;
                else if (*q2 == ':' && nest == 0)
                else if (*q2 == ':' && nest == 0)
                  break;
                  break;
              }
              }
            p = q2;
            p = q2;
            if (*p != ':')
            if (*p != ':')
              {
              {
                bad_stab (orig);
                bad_stab (orig);
                return DEBUG_TYPE_NULL;
                return DEBUG_TYPE_NULL;
              }
              }
          }
          }
 
 
        /* Some versions of g++ can emit stabs like
        /* Some versions of g++ can emit stabs like
               fleep:T20=xsfleep:
               fleep:T20=xsfleep:
           which define structures in terms of themselves.  We need to
           which define structures in terms of themselves.  We need to
           tell the caller to avoid building a circular structure.  */
           tell the caller to avoid building a circular structure.  */
        if (type_name != NULL
        if (type_name != NULL
            && strncmp (type_name, *pp, p - *pp) == 0
            && strncmp (type_name, *pp, p - *pp) == 0
            && type_name[p - *pp] == '\0')
            && type_name[p - *pp] == '\0')
          info->self_crossref = TRUE;
          info->self_crossref = TRUE;
 
 
        dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code);
        dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code);
 
 
        *pp = p + 1;
        *pp = p + 1;
      }
      }
      break;
      break;
 
 
    case '-':
    case '-':
    case '0':
    case '0':
    case '1':
    case '1':
    case '2':
    case '2':
    case '3':
    case '3':
    case '4':
    case '4':
    case '5':
    case '5':
    case '6':
    case '6':
    case '7':
    case '7':
    case '8':
    case '8':
    case '9':
    case '9':
    case '(':
    case '(':
      {
      {
        const char *hold;
        const char *hold;
        int xtypenums[2];
        int xtypenums[2];
 
 
        /* This type is defined as another type.  */
        /* This type is defined as another type.  */
        (*pp)--;
        (*pp)--;
        hold = *pp;
        hold = *pp;
 
 
        /* Peek ahead at the number to detect void.  */
        /* Peek ahead at the number to detect void.  */
        if (! parse_stab_type_number (pp, xtypenums))
        if (! parse_stab_type_number (pp, xtypenums))
          return DEBUG_TYPE_NULL;
          return DEBUG_TYPE_NULL;
 
 
        if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
        if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1])
          {
          {
            /* This type is being defined as itself, which means that
            /* This type is being defined as itself, which means that
               it is void.  */
               it is void.  */
            dtype = debug_make_void_type (dhandle);
            dtype = debug_make_void_type (dhandle);
          }
          }
        else
        else
          {
          {
            *pp = hold;
            *pp = hold;
 
 
            /* Go back to the number and have parse_stab_type get it.
            /* Go back to the number and have parse_stab_type get it.
               This means that we can deal with something like
               This means that we can deal with something like
               t(1,2)=(3,4)=... which the Lucid compiler uses.  */
               t(1,2)=(3,4)=... which the Lucid compiler uses.  */
            dtype = parse_stab_type (dhandle, info, (const char *) NULL,
            dtype = parse_stab_type (dhandle, info, (const char *) NULL,
                                     pp, (debug_type **) NULL);
                                     pp, (debug_type **) NULL);
            if (dtype == DEBUG_TYPE_NULL)
            if (dtype == DEBUG_TYPE_NULL)
              return DEBUG_TYPE_NULL;
              return DEBUG_TYPE_NULL;
          }
          }
 
 
        if (typenums[0] != -1)
        if (typenums[0] != -1)
          {
          {
            if (! stab_record_type (dhandle, info, typenums, dtype))
            if (! stab_record_type (dhandle, info, typenums, dtype))
              return DEBUG_TYPE_NULL;
              return DEBUG_TYPE_NULL;
          }
          }
 
 
        break;
        break;
      }
      }
 
 
    case '*':
    case '*':
      dtype = debug_make_pointer_type (dhandle,
      dtype = debug_make_pointer_type (dhandle,
                                       parse_stab_type (dhandle, info,
                                       parse_stab_type (dhandle, info,
                                                        (const char *) NULL,
                                                        (const char *) NULL,
                                                        pp,
                                                        pp,
                                                        (debug_type **) NULL));
                                                        (debug_type **) NULL));
      break;
      break;
 
 
    case '&':
    case '&':
      /* Reference to another type.  */
      /* Reference to another type.  */
      dtype = (debug_make_reference_type
      dtype = (debug_make_reference_type
               (dhandle,
               (dhandle,
                parse_stab_type (dhandle, info, (const char *) NULL, pp,
                parse_stab_type (dhandle, info, (const char *) NULL, pp,
                                 (debug_type **) NULL)));
                                 (debug_type **) NULL)));
      break;
      break;
 
 
    case 'f':
    case 'f':
      /* Function returning another type.  */
      /* Function returning another type.  */
      /* FIXME: gdb checks os9k_stabs here.  */
      /* FIXME: gdb checks os9k_stabs here.  */
      dtype = (debug_make_function_type
      dtype = (debug_make_function_type
               (dhandle,
               (dhandle,
                parse_stab_type (dhandle, info, (const char *) NULL, pp,
                parse_stab_type (dhandle, info, (const char *) NULL, pp,
                                 (debug_type **) NULL),
                                 (debug_type **) NULL),
                (debug_type *) NULL, FALSE));
                (debug_type *) NULL, FALSE));
      break;
      break;
 
 
    case 'k':
    case 'k':
      /* Const qualifier on some type (Sun).  */
      /* Const qualifier on some type (Sun).  */
      /* FIXME: gdb accepts 'c' here if os9k_stabs.  */
      /* FIXME: gdb accepts 'c' here if os9k_stabs.  */
      dtype = debug_make_const_type (dhandle,
      dtype = debug_make_const_type (dhandle,
                                     parse_stab_type (dhandle, info,
                                     parse_stab_type (dhandle, info,
                                                      (const char *) NULL,
                                                      (const char *) NULL,
                                                      pp,
                                                      pp,
                                                      (debug_type **) NULL));
                                                      (debug_type **) NULL));
      break;
      break;
 
 
    case 'B':
    case 'B':
      /* Volatile qual on some type (Sun).  */
      /* Volatile qual on some type (Sun).  */
      /* FIXME: gdb accepts 'i' here if os9k_stabs.  */
      /* FIXME: gdb accepts 'i' here if os9k_stabs.  */
      dtype = (debug_make_volatile_type
      dtype = (debug_make_volatile_type
               (dhandle,
               (dhandle,
                parse_stab_type (dhandle, info, (const char *) NULL, pp,
                parse_stab_type (dhandle, info, (const char *) NULL, pp,
                                 (debug_type **) NULL)));
                                 (debug_type **) NULL)));
      break;
      break;
 
 
    case '@':
    case '@':
      /* Offset (class & variable) type.  This is used for a pointer
      /* Offset (class & variable) type.  This is used for a pointer
         relative to an object.  */
         relative to an object.  */
      {
      {
        debug_type domain;
        debug_type domain;
        debug_type memtype;
        debug_type memtype;
 
 
        /* Member type.  */
        /* Member type.  */
 
 
        domain = parse_stab_type (dhandle, info, (const char *) NULL, pp,
        domain = parse_stab_type (dhandle, info, (const char *) NULL, pp,
                                  (debug_type **) NULL);
                                  (debug_type **) NULL);
        if (domain == DEBUG_TYPE_NULL)
        if (domain == DEBUG_TYPE_NULL)
          return DEBUG_TYPE_NULL;
          return DEBUG_TYPE_NULL;
 
 
        if (**pp != ',')
        if (**pp != ',')
          {
          {
            bad_stab (orig);
            bad_stab (orig);
            return DEBUG_TYPE_NULL;
            return DEBUG_TYPE_NULL;
          }
          }
        ++*pp;
        ++*pp;
 
 
        memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
        memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
                                   (debug_type **) NULL);
                                   (debug_type **) NULL);
        if (memtype == DEBUG_TYPE_NULL)
        if (memtype == DEBUG_TYPE_NULL)
          return DEBUG_TYPE_NULL;
          return DEBUG_TYPE_NULL;
 
 
        dtype = debug_make_offset_type (dhandle, domain, memtype);
        dtype = debug_make_offset_type (dhandle, domain, memtype);
      }
      }
      break;
      break;
 
 
    case '#':
    case '#':
      /* Method (class & fn) type.  */
      /* Method (class & fn) type.  */
      if (**pp == '#')
      if (**pp == '#')
        {
        {
          debug_type return_type;
          debug_type return_type;
 
 
          ++*pp;
          ++*pp;
          return_type = parse_stab_type (dhandle, info, (const char *) NULL,
          return_type = parse_stab_type (dhandle, info, (const char *) NULL,
                                         pp, (debug_type **) NULL);
                                         pp, (debug_type **) NULL);
          if (return_type == DEBUG_TYPE_NULL)
          if (return_type == DEBUG_TYPE_NULL)
            return DEBUG_TYPE_NULL;
            return DEBUG_TYPE_NULL;
          if (**pp != ';')
          if (**pp != ';')
            {
            {
              bad_stab (orig);
              bad_stab (orig);
              return DEBUG_TYPE_NULL;
              return DEBUG_TYPE_NULL;
            }
            }
          ++*pp;
          ++*pp;
          dtype = debug_make_method_type (dhandle, return_type,
          dtype = debug_make_method_type (dhandle, return_type,
                                          DEBUG_TYPE_NULL,
                                          DEBUG_TYPE_NULL,
                                          (debug_type *) NULL, FALSE);
                                          (debug_type *) NULL, FALSE);
        }
        }
      else
      else
        {
        {
          debug_type domain;
          debug_type domain;
          debug_type return_type;
          debug_type return_type;
          debug_type *args;
          debug_type *args;
          unsigned int n;
          unsigned int n;
          unsigned int alloc;
          unsigned int alloc;
          bfd_boolean varargs;
          bfd_boolean varargs;
 
 
          domain = parse_stab_type (dhandle, info, (const char *) NULL,
          domain = parse_stab_type (dhandle, info, (const char *) NULL,
                                    pp, (debug_type **) NULL);
                                    pp, (debug_type **) NULL);
          if (domain == DEBUG_TYPE_NULL)
          if (domain == DEBUG_TYPE_NULL)
            return DEBUG_TYPE_NULL;
            return DEBUG_TYPE_NULL;
 
 
          if (**pp != ',')
          if (**pp != ',')
            {
            {
              bad_stab (orig);
              bad_stab (orig);
              return DEBUG_TYPE_NULL;
              return DEBUG_TYPE_NULL;
            }
            }
          ++*pp;
          ++*pp;
 
 
          return_type = parse_stab_type (dhandle, info, (const char *) NULL,
          return_type = parse_stab_type (dhandle, info, (const char *) NULL,
                                         pp, (debug_type **) NULL);
                                         pp, (debug_type **) NULL);
          if (return_type == DEBUG_TYPE_NULL)
          if (return_type == DEBUG_TYPE_NULL)
            return DEBUG_TYPE_NULL;
            return DEBUG_TYPE_NULL;
 
 
          alloc = 10;
          alloc = 10;
          args = (debug_type *) xmalloc (alloc * sizeof *args);
          args = (debug_type *) xmalloc (alloc * sizeof *args);
          n = 0;
          n = 0;
          while (**pp != ';')
          while (**pp != ';')
            {
            {
              if (**pp != ',')
              if (**pp != ',')
                {
                {
                  bad_stab (orig);
                  bad_stab (orig);
                  return DEBUG_TYPE_NULL;
                  return DEBUG_TYPE_NULL;
                }
                }
              ++*pp;
              ++*pp;
 
 
              if (n + 1 >= alloc)
              if (n + 1 >= alloc)
                {
                {
                  alloc += 10;
                  alloc += 10;
                  args = ((debug_type *)
                  args = ((debug_type *)
                          xrealloc (args, alloc * sizeof *args));
                          xrealloc (args, alloc * sizeof *args));
                }
                }
 
 
              args[n] = parse_stab_type (dhandle, info, (const char *) NULL,
              args[n] = parse_stab_type (dhandle, info, (const char *) NULL,
                                         pp, (debug_type **) NULL);
                                         pp, (debug_type **) NULL);
              if (args[n] == DEBUG_TYPE_NULL)
              if (args[n] == DEBUG_TYPE_NULL)
                return DEBUG_TYPE_NULL;
                return DEBUG_TYPE_NULL;
              ++n;
              ++n;
            }
            }
          ++*pp;
          ++*pp;
 
 
          /* If the last type is not void, then this function takes a
          /* If the last type is not void, then this function takes a
             variable number of arguments.  Otherwise, we must strip
             variable number of arguments.  Otherwise, we must strip
             the void type.  */
             the void type.  */
          if (n == 0
          if (n == 0
              || debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID)
              || debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID)
            varargs = TRUE;
            varargs = TRUE;
          else
          else
            {
            {
              --n;
              --n;
              varargs = FALSE;
              varargs = FALSE;
            }
            }
 
 
          args[n] = DEBUG_TYPE_NULL;
          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);
                                          varargs);
        }
        }
      break;
      break;
 
 
    case 'r':
    case 'r':
      /* Range type.  */
      /* Range type.  */
      dtype = parse_stab_range_type (dhandle, info, type_name, pp, typenums);
      dtype = parse_stab_range_type (dhandle, info, type_name, pp, typenums);
      break;
      break;
 
 
    case 'b':
    case 'b':
      /* FIXME: gdb checks os9k_stabs here.  */
      /* FIXME: gdb checks os9k_stabs here.  */
      /* Sun ACC builtin int type.  */
      /* Sun ACC builtin int type.  */
      dtype = parse_stab_sun_builtin_type (dhandle, pp);
      dtype = parse_stab_sun_builtin_type (dhandle, pp);
      break;
      break;
 
 
    case 'R':
    case 'R':
      /* Sun ACC builtin float type.  */
      /* Sun ACC builtin float type.  */
      dtype = parse_stab_sun_floating_type (dhandle, pp);
      dtype = parse_stab_sun_floating_type (dhandle, pp);
      break;
      break;
 
 
    case 'e':
    case 'e':
      /* Enumeration type.  */
      /* Enumeration type.  */
      dtype = parse_stab_enum_type (dhandle, pp);
      dtype = parse_stab_enum_type (dhandle, pp);
      break;
      break;
 
 
    case 's':
    case 's':
    case 'u':
    case 'u':
      /* Struct or union type.  */
      /* Struct or union type.  */
      dtype = parse_stab_struct_type (dhandle, info, type_name, pp,
      dtype = parse_stab_struct_type (dhandle, info, type_name, pp,
                                      descriptor == 's', typenums);
                                      descriptor == 's', typenums);
      break;
      break;
 
 
    case 'a':
    case 'a':
      /* Array type.  */
      /* Array type.  */
      if (**pp != 'r')
      if (**pp != 'r')
        {
        {
          bad_stab (orig);
          bad_stab (orig);
          return DEBUG_TYPE_NULL;
          return DEBUG_TYPE_NULL;
        }
        }
      ++*pp;
      ++*pp;
 
 
      dtype = parse_stab_array_type (dhandle, info, pp, stringp);
      dtype = parse_stab_array_type (dhandle, info, pp, stringp);
      break;
      break;
 
 
    case 'S':
    case 'S':
      dtype = debug_make_set_type (dhandle,
      dtype = debug_make_set_type (dhandle,
                                   parse_stab_type (dhandle, info,
                                   parse_stab_type (dhandle, info,
                                                    (const char *) NULL,
                                                    (const char *) NULL,
                                                    pp,
                                                    pp,
                                                    (debug_type **) NULL),
                                                    (debug_type **) NULL),
                                   stringp);
                                   stringp);
      break;
      break;
 
 
    default:
    default:
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
 
 
  if (dtype == DEBUG_TYPE_NULL)
  if (dtype == DEBUG_TYPE_NULL)
    return DEBUG_TYPE_NULL;
    return DEBUG_TYPE_NULL;
 
 
  if (typenums[0] != -1)
  if (typenums[0] != -1)
    {
    {
      if (! stab_record_type (dhandle, info, typenums, dtype))
      if (! stab_record_type (dhandle, info, typenums, dtype))
        return DEBUG_TYPE_NULL;
        return DEBUG_TYPE_NULL;
    }
    }
 
 
  if (size != -1)
  if (size != -1)
    {
    {
      if (! debug_record_type_size (dhandle, dtype, (unsigned int) size))
      if (! debug_record_type_size (dhandle, dtype, (unsigned int) size))
        return DEBUG_TYPE_NULL;
        return DEBUG_TYPE_NULL;
    }
    }
 
 
  return dtype;
  return dtype;
}
}
 
 
/* Read a number by which a type is referred to in dbx data, or
/* Read a number by which a type is referred to in dbx data, or
   perhaps read a pair (FILENUM, TYPENUM) in parentheses.  Just a
   perhaps read a pair (FILENUM, TYPENUM) in parentheses.  Just a
   single number N is equivalent to (0,N).  Return the two numbers by
   single number N is equivalent to (0,N).  Return the two numbers by
   storing them in the vector TYPENUMS.  */
   storing them in the vector TYPENUMS.  */
 
 
static bfd_boolean
static bfd_boolean
parse_stab_type_number (const char **pp, int *typenums)
parse_stab_type_number (const char **pp, int *typenums)
{
{
  const char *orig;
  const char *orig;
 
 
  orig = *pp;
  orig = *pp;
 
 
  if (**pp != '(')
  if (**pp != '(')
    {
    {
      typenums[0] = 0;
      typenums[0] = 0;
      typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL);
      typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL);
    }
    }
  else
  else
    {
    {
      ++*pp;
      ++*pp;
      typenums[0] = (int) parse_number (pp, (bfd_boolean *) NULL);
      typenums[0] = (int) parse_number (pp, (bfd_boolean *) NULL);
      if (**pp != ',')
      if (**pp != ',')
        {
        {
          bad_stab (orig);
          bad_stab (orig);
          return FALSE;
          return FALSE;
        }
        }
      ++*pp;
      ++*pp;
      typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL);
      typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL);
      if (**pp != ')')
      if (**pp != ')')
        {
        {
          bad_stab (orig);
          bad_stab (orig);
          return FALSE;
          return FALSE;
        }
        }
      ++*pp;
      ++*pp;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Parse a range type.  */
/* Parse a range type.  */
 
 
static debug_type
static debug_type
parse_stab_range_type (void *dhandle, struct stab_handle *info, const char *type_name, const char **pp, const int *typenums)
parse_stab_range_type (void *dhandle, struct stab_handle *info, const char *type_name, const char **pp, const int *typenums)
{
{
  const char *orig;
  const char *orig;
  int rangenums[2];
  int rangenums[2];
  bfd_boolean self_subrange;
  bfd_boolean self_subrange;
  debug_type index_type;
  debug_type index_type;
  const char *s2, *s3;
  const char *s2, *s3;
  bfd_signed_vma n2, n3;
  bfd_signed_vma n2, n3;
  bfd_boolean ov2, ov3;
  bfd_boolean ov2, ov3;
 
 
  orig = *pp;
  orig = *pp;
 
 
  index_type = DEBUG_TYPE_NULL;
  index_type = DEBUG_TYPE_NULL;
 
 
  /* First comes a type we are a subrange of.
  /* First comes a type we are a subrange of.
     In C it is usually 0, 1 or the type being defined.  */
     In C it is usually 0, 1 or the type being defined.  */
  if (! parse_stab_type_number (pp, rangenums))
  if (! parse_stab_type_number (pp, rangenums))
    return DEBUG_TYPE_NULL;
    return DEBUG_TYPE_NULL;
 
 
  self_subrange = (rangenums[0] == typenums[0]
  self_subrange = (rangenums[0] == typenums[0]
                   && rangenums[1] == typenums[1]);
                   && rangenums[1] == typenums[1]);
 
 
  if (**pp == '=')
  if (**pp == '=')
    {
    {
      *pp = orig;
      *pp = orig;
      index_type = parse_stab_type (dhandle, info, (const char *) NULL,
      index_type = parse_stab_type (dhandle, info, (const char *) NULL,
                                    pp, (debug_type **) NULL);
                                    pp, (debug_type **) NULL);
      if (index_type == DEBUG_TYPE_NULL)
      if (index_type == DEBUG_TYPE_NULL)
        return DEBUG_TYPE_NULL;
        return DEBUG_TYPE_NULL;
    }
    }
 
 
  if (**pp == ';')
  if (**pp == ';')
    ++*pp;
    ++*pp;
 
 
  /* The remaining two operands are usually lower and upper bounds of
  /* The remaining two operands are usually lower and upper bounds of
     the range.  But in some special cases they mean something else.  */
     the range.  But in some special cases they mean something else.  */
  s2 = *pp;
  s2 = *pp;
  n2 = parse_number (pp, &ov2);
  n2 = parse_number (pp, &ov2);
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
  ++*pp;
  ++*pp;
 
 
  s3 = *pp;
  s3 = *pp;
  n3 = parse_number (pp, &ov3);
  n3 = parse_number (pp, &ov3);
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
  ++*pp;
  ++*pp;
 
 
  if (ov2 || ov3)
  if (ov2 || ov3)
    {
    {
      /* gcc will emit range stabs for long long types.  Handle this
      /* gcc will emit range stabs for long long types.  Handle this
         as a special case.  FIXME: This needs to be more general.  */
         as a special case.  FIXME: This needs to be more general.  */
#define LLLOW   "01000000000000000000000;"
#define LLLOW   "01000000000000000000000;"
#define LLHIGH   "0777777777777777777777;"
#define LLHIGH   "0777777777777777777777;"
#define ULLHIGH "01777777777777777777777;"
#define ULLHIGH "01777777777777777777777;"
      if (index_type == DEBUG_TYPE_NULL)
      if (index_type == DEBUG_TYPE_NULL)
        {
        {
          if (CONST_STRNEQ (s2, LLLOW)
          if (CONST_STRNEQ (s2, LLLOW)
              && CONST_STRNEQ (s3, LLHIGH))
              && CONST_STRNEQ (s3, LLHIGH))
            return debug_make_int_type (dhandle, 8, FALSE);
            return debug_make_int_type (dhandle, 8, FALSE);
          if (! ov2
          if (! ov2
              && n2 == 0
              && n2 == 0
              && CONST_STRNEQ (s3, ULLHIGH))
              && CONST_STRNEQ (s3, ULLHIGH))
            return debug_make_int_type (dhandle, 8, TRUE);
            return debug_make_int_type (dhandle, 8, TRUE);
        }
        }
 
 
      warn_stab (orig, _("numeric overflow"));
      warn_stab (orig, _("numeric overflow"));
    }
    }
 
 
  if (index_type == DEBUG_TYPE_NULL)
  if (index_type == DEBUG_TYPE_NULL)
    {
    {
      /* A type defined as a subrange of itself, with both bounds 0,
      /* A type defined as a subrange of itself, with both bounds 0,
         is void.  */
         is void.  */
      if (self_subrange && n2 == 0 && n3 == 0)
      if (self_subrange && n2 == 0 && n3 == 0)
        return debug_make_void_type (dhandle);
        return debug_make_void_type (dhandle);
 
 
      /* A type defined as a subrange of itself, with n2 positive and
      /* 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.  */
         n3 zero, is a complex type, and n2 is the number of bytes.  */
      if (self_subrange && n3 == 0 && n2 > 0)
      if (self_subrange && n3 == 0 && n2 > 0)
        return debug_make_complex_type (dhandle, n2);
        return debug_make_complex_type (dhandle, n2);
 
 
      /* If n3 is zero and n2 is positive, this is a floating point
      /* If n3 is zero and n2 is positive, this is a floating point
         type, and n2 is the number of bytes.  */
         type, and n2 is the number of bytes.  */
      if (n3 == 0 && n2 > 0)
      if (n3 == 0 && n2 > 0)
        return debug_make_float_type (dhandle, n2);
        return debug_make_float_type (dhandle, n2);
 
 
      /* If the upper bound is -1, this is an unsigned int.  */
      /* If the upper bound is -1, this is an unsigned int.  */
      if (n2 == 0 && n3 == -1)
      if (n2 == 0 && n3 == -1)
        {
        {
          /* When gcc is used with -gstabs, but not -gstabs+, it will emit
          /* When gcc is used with -gstabs, but not -gstabs+, it will emit
                 long long int:t6=r1;0;-1;
                 long long int:t6=r1;0;-1;
                 long long unsigned int:t7=r1;0;-1;
                 long long unsigned int:t7=r1;0;-1;
             We hack here to handle this reasonably.  */
             We hack here to handle this reasonably.  */
          if (type_name != NULL)
          if (type_name != NULL)
            {
            {
              if (strcmp (type_name, "long long int") == 0)
              if (strcmp (type_name, "long long int") == 0)
                return debug_make_int_type (dhandle, 8, FALSE);
                return debug_make_int_type (dhandle, 8, FALSE);
              else if (strcmp (type_name, "long long unsigned int") == 0)
              else if (strcmp (type_name, "long long unsigned int") == 0)
                return debug_make_int_type (dhandle, 8, TRUE);
                return debug_make_int_type (dhandle, 8, TRUE);
            }
            }
          /* FIXME: The size here really depends upon the target.  */
          /* FIXME: The size here really depends upon the target.  */
          return debug_make_int_type (dhandle, 4, TRUE);
          return debug_make_int_type (dhandle, 4, TRUE);
        }
        }
 
 
      /* A range of 0 to 127 is char.  */
      /* A range of 0 to 127 is char.  */
      if (self_subrange && n2 == 0 && n3 == 127)
      if (self_subrange && n2 == 0 && n3 == 127)
        return debug_make_int_type (dhandle, 1, FALSE);
        return debug_make_int_type (dhandle, 1, FALSE);
 
 
      /* FIXME: gdb checks for the language CHILL here.  */
      /* FIXME: gdb checks for the language CHILL here.  */
 
 
      if (n2 == 0)
      if (n2 == 0)
        {
        {
          if (n3 < 0)
          if (n3 < 0)
            return debug_make_int_type (dhandle, - n3, TRUE);
            return debug_make_int_type (dhandle, - n3, TRUE);
          else if (n3 == 0xff)
          else if (n3 == 0xff)
            return debug_make_int_type (dhandle, 1, TRUE);
            return debug_make_int_type (dhandle, 1, TRUE);
          else if (n3 == 0xffff)
          else if (n3 == 0xffff)
            return debug_make_int_type (dhandle, 2, TRUE);
            return debug_make_int_type (dhandle, 2, TRUE);
          else if (n3 == (bfd_signed_vma) 0xffffffff)
          else if (n3 == (bfd_signed_vma) 0xffffffff)
            return debug_make_int_type (dhandle, 4, TRUE);
            return debug_make_int_type (dhandle, 4, TRUE);
#ifdef BFD64
#ifdef BFD64
          else if (n3 == ((((bfd_signed_vma) 0xffffffff) << 32) | 0xffffffff))
          else if (n3 == ((((bfd_signed_vma) 0xffffffff) << 32) | 0xffffffff))
            return debug_make_int_type (dhandle, 8, TRUE);
            return debug_make_int_type (dhandle, 8, TRUE);
#endif
#endif
        }
        }
      else if (n3 == 0
      else if (n3 == 0
               && n2 < 0
               && n2 < 0
               && (self_subrange || n2 == -8))
               && (self_subrange || n2 == -8))
        return debug_make_int_type (dhandle, - n2, TRUE);
        return debug_make_int_type (dhandle, - n2, TRUE);
      else if (n2 == - n3 - 1 || n2 == n3 + 1)
      else if (n2 == - n3 - 1 || n2 == n3 + 1)
        {
        {
          if (n3 == 0x7f)
          if (n3 == 0x7f)
            return debug_make_int_type (dhandle, 1, FALSE);
            return debug_make_int_type (dhandle, 1, FALSE);
          else if (n3 == 0x7fff)
          else if (n3 == 0x7fff)
            return debug_make_int_type (dhandle, 2, FALSE);
            return debug_make_int_type (dhandle, 2, FALSE);
          else if (n3 == 0x7fffffff)
          else if (n3 == 0x7fffffff)
            return debug_make_int_type (dhandle, 4, FALSE);
            return debug_make_int_type (dhandle, 4, FALSE);
#ifdef BFD64
#ifdef BFD64
          else if (n3 == ((((bfd_vma) 0x7fffffff) << 32) | 0xffffffff))
          else if (n3 == ((((bfd_vma) 0x7fffffff) << 32) | 0xffffffff))
            return debug_make_int_type (dhandle, 8, FALSE);
            return debug_make_int_type (dhandle, 8, FALSE);
#endif
#endif
        }
        }
    }
    }
 
 
  /* At this point I don't have the faintest idea how to deal with a
  /* At this point I don't have the faintest idea how to deal with a
     self_subrange type; I'm going to assume that this is used as an
     self_subrange type; I'm going to assume that this is used as an
     idiom, and that all of them are special cases.  So . . .  */
     idiom, and that all of them are special cases.  So . . .  */
  if (self_subrange)
  if (self_subrange)
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
 
 
  index_type = stab_find_type (dhandle, info, rangenums);
  index_type = stab_find_type (dhandle, info, rangenums);
  if (index_type == DEBUG_TYPE_NULL)
  if (index_type == DEBUG_TYPE_NULL)
    {
    {
      /* Does this actually ever happen?  Is that why we are worrying
      /* Does this actually ever happen?  Is that why we are worrying
         about dealing with it rather than just calling error_type?  */
         about dealing with it rather than just calling error_type?  */
      warn_stab (orig, _("missing index type"));
      warn_stab (orig, _("missing index type"));
      index_type = debug_make_int_type (dhandle, 4, FALSE);
      index_type = debug_make_int_type (dhandle, 4, FALSE);
    }
    }
 
 
  return debug_make_range_type (dhandle, index_type, n2, n3);
  return debug_make_range_type (dhandle, index_type, n2, n3);
}
}
 
 
/* Sun's ACC uses a somewhat saner method for specifying the builtin
/* Sun's ACC uses a somewhat saner method for specifying the builtin
   typedefs in every file (for int, long, etc):
   typedefs in every file (for int, long, etc):
 
 
        type = b <signed> <width>; <offset>; <nbits>
        type = b <signed> <width>; <offset>; <nbits>
        signed = u or s.  Possible c in addition to u or s (for char?).
        signed = u or s.  Possible c in addition to u or s (for char?).
        offset = offset from high order bit to start bit of type.
        offset = offset from high order bit to start bit of type.
        width is # bytes in object of this type, nbits is # bits in type.
        width is # bytes in object of this type, nbits is # bits in type.
 
 
   The width/offset stuff appears to be for small objects stored in
   The width/offset stuff appears to be for small objects stored in
   larger ones (e.g. `shorts' in `int' registers).  We ignore it for now,
   larger ones (e.g. `shorts' in `int' registers).  We ignore it for now,
   FIXME.  */
   FIXME.  */
 
 
static debug_type
static debug_type
parse_stab_sun_builtin_type (void *dhandle, const char **pp)
parse_stab_sun_builtin_type (void *dhandle, const char **pp)
{
{
  const char *orig;
  const char *orig;
  bfd_boolean unsignedp;
  bfd_boolean unsignedp;
  bfd_vma bits;
  bfd_vma bits;
 
 
  orig = *pp;
  orig = *pp;
 
 
  switch (**pp)
  switch (**pp)
    {
    {
    case 's':
    case 's':
      unsignedp = FALSE;
      unsignedp = FALSE;
      break;
      break;
    case 'u':
    case 'u':
      unsignedp = TRUE;
      unsignedp = TRUE;
      break;
      break;
    default:
    default:
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
  ++*pp;
  ++*pp;
 
 
  /* OpenSolaris source code indicates that one of "cbv" characters
  /* OpenSolaris source code indicates that one of "cbv" characters
     can come next and specify the intrinsic 'iformat' encoding.
     can come next and specify the intrinsic 'iformat' encoding.
     'c' is character encoding, 'b' is boolean encoding, and 'v' is
     'c' is character encoding, 'b' is boolean encoding, and 'v' is
     varargs encoding.  This field can be safely ignored because
     varargs encoding.  This field can be safely ignored because
     the type of the field is determined from the bitwidth extracted
     the type of the field is determined from the bitwidth extracted
     below.  */
     below.  */
  if (**pp == 'c' || **pp == 'b' || **pp == 'v')
  if (**pp == 'c' || **pp == 'b' || **pp == 'v')
    ++*pp;
    ++*pp;
 
 
  /* The first number appears to be the number of bytes occupied
  /* The first number appears to be the number of bytes occupied
     by this type, except that unsigned short is 4 instead of 2.
     by this type, except that unsigned short is 4 instead of 2.
     Since this information is redundant with the third number,
     Since this information is redundant with the third number,
     we will ignore it.  */
     we will ignore it.  */
  (void) parse_number (pp, (bfd_boolean *) NULL);
  (void) parse_number (pp, (bfd_boolean *) NULL);
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
  ++*pp;
  ++*pp;
 
 
  /* The second number is always 0, so ignore it too.  */
  /* The second number is always 0, so ignore it too.  */
  (void) parse_number (pp, (bfd_boolean *) NULL);
  (void) parse_number (pp, (bfd_boolean *) NULL);
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
  ++*pp;
  ++*pp;
 
 
  /* The third number is the number of bits for this type.  */
  /* The third number is the number of bits for this type.  */
  bits = parse_number (pp, (bfd_boolean *) NULL);
  bits = parse_number (pp, (bfd_boolean *) NULL);
 
 
  /* The type *should* end with a semicolon.  If it are embedded
  /* The type *should* end with a semicolon.  If it are embedded
     in a larger type the semicolon may be the only way to know where
     in a larger type the semicolon may be the only way to know where
     the type ends.  If this type is at the end of the stabstring we
     the type ends.  If this type is at the end of the stabstring we
     can deal with the omitted semicolon (but we don't have to like
     can deal with the omitted semicolon (but we don't have to like
     it).  Don't bother to complain(), Sun's compiler omits the semicolon
     it).  Don't bother to complain(), Sun's compiler omits the semicolon
     for "void".  */
     for "void".  */
  if (**pp == ';')
  if (**pp == ';')
    ++*pp;
    ++*pp;
 
 
  if (bits == 0)
  if (bits == 0)
    return debug_make_void_type (dhandle);
    return debug_make_void_type (dhandle);
 
 
  return debug_make_int_type (dhandle, bits / 8, unsignedp);
  return debug_make_int_type (dhandle, bits / 8, unsignedp);
}
}
 
 
/* Parse a builtin floating type generated by the Sun compiler.  */
/* Parse a builtin floating type generated by the Sun compiler.  */
 
 
static debug_type
static debug_type
parse_stab_sun_floating_type (void *dhandle, const char **pp)
parse_stab_sun_floating_type (void *dhandle, const char **pp)
{
{
  const char *orig;
  const char *orig;
  bfd_vma details;
  bfd_vma details;
  bfd_vma bytes;
  bfd_vma bytes;
 
 
  orig = *pp;
  orig = *pp;
 
 
  /* The first number has more details about the type, for example
  /* The first number has more details about the type, for example
     FN_COMPLEX.  */
     FN_COMPLEX.  */
  details = parse_number (pp, (bfd_boolean *) NULL);
  details = parse_number (pp, (bfd_boolean *) NULL);
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
 
 
  /* The second number is the number of bytes occupied by this type */
  /* The second number is the number of bytes occupied by this type */
  bytes = parse_number (pp, (bfd_boolean *) NULL);
  bytes = parse_number (pp, (bfd_boolean *) NULL);
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
 
 
  if (details == NF_COMPLEX
  if (details == NF_COMPLEX
      || details == NF_COMPLEX16
      || details == NF_COMPLEX16
      || details == NF_COMPLEX32)
      || details == NF_COMPLEX32)
    return debug_make_complex_type (dhandle, bytes);
    return debug_make_complex_type (dhandle, bytes);
 
 
  return debug_make_float_type (dhandle, bytes);
  return debug_make_float_type (dhandle, bytes);
}
}
 
 
/* Handle an enum type.  */
/* Handle an enum type.  */
 
 
static debug_type
static debug_type
parse_stab_enum_type (void *dhandle, const char **pp)
parse_stab_enum_type (void *dhandle, const char **pp)
{
{
  const char *orig;
  const char *orig;
  const char **names;
  const char **names;
  bfd_signed_vma *values;
  bfd_signed_vma *values;
  unsigned int n;
  unsigned int n;
  unsigned int alloc;
  unsigned int alloc;
 
 
  orig = *pp;
  orig = *pp;
 
 
  /* FIXME: gdb checks os9k_stabs here.  */
  /* FIXME: gdb checks os9k_stabs here.  */
 
 
  /* The aix4 compiler emits an extra field before the enum members;
  /* The aix4 compiler emits an extra field before the enum members;
     my guess is it's a type of some sort.  Just ignore it.  */
     my guess is it's a type of some sort.  Just ignore it.  */
  if (**pp == '-')
  if (**pp == '-')
    {
    {
      while (**pp != ':')
      while (**pp != ':')
        ++*pp;
        ++*pp;
      ++*pp;
      ++*pp;
    }
    }
 
 
  /* Read the value-names and their values.
  /* Read the value-names and their values.
     The input syntax is NAME:VALUE,NAME:VALUE, and so on.
     The input syntax is NAME:VALUE,NAME:VALUE, and so on.
     A semicolon or comma instead of a NAME means the end.  */
     A semicolon or comma instead of a NAME means the end.  */
  alloc = 10;
  alloc = 10;
  names = (const char **) xmalloc (alloc * sizeof *names);
  names = (const char **) xmalloc (alloc * sizeof *names);
  values = (bfd_signed_vma *) xmalloc (alloc * sizeof *values);
  values = (bfd_signed_vma *) xmalloc (alloc * sizeof *values);
  n = 0;
  n = 0;
  while (**pp != '\0' && **pp != ';' && **pp != ',')
  while (**pp != '\0' && **pp != ';' && **pp != ',')
    {
    {
      const char *p;
      const char *p;
      char *name;
      char *name;
      bfd_signed_vma val;
      bfd_signed_vma val;
 
 
      p = *pp;
      p = *pp;
      while (*p != ':')
      while (*p != ':')
        ++p;
        ++p;
 
 
      name = savestring (*pp, p - *pp);
      name = savestring (*pp, p - *pp);
 
 
      *pp = p + 1;
      *pp = p + 1;
      val = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
      val = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
      if (**pp != ',')
      if (**pp != ',')
        {
        {
          bad_stab (orig);
          bad_stab (orig);
          return DEBUG_TYPE_NULL;
          return DEBUG_TYPE_NULL;
        }
        }
      ++*pp;
      ++*pp;
 
 
      if (n + 1 >= alloc)
      if (n + 1 >= alloc)
        {
        {
          alloc += 10;
          alloc += 10;
          names = ((const char **)
          names = ((const char **)
                   xrealloc (names, alloc * sizeof *names));
                   xrealloc (names, alloc * sizeof *names));
          values = ((bfd_signed_vma *)
          values = ((bfd_signed_vma *)
                    xrealloc (values, alloc * sizeof *values));
                    xrealloc (values, alloc * sizeof *values));
        }
        }
 
 
      names[n] = name;
      names[n] = name;
      values[n] = val;
      values[n] = val;
      ++n;
      ++n;
    }
    }
 
 
  names[n] = NULL;
  names[n] = NULL;
  values[n] = 0;
  values[n] = 0;
 
 
  if (**pp == ';')
  if (**pp == ';')
    ++*pp;
    ++*pp;
 
 
  return debug_make_enum_type (dhandle, names, values);
  return debug_make_enum_type (dhandle, names, values);
}
}
 
 
/* Read the description of a structure (or union type) and return an object
/* Read the description of a structure (or union type) and return an object
   describing the type.
   describing the type.
 
 
   PP points to a character pointer that points to the next unconsumed token
   PP points to a character pointer that points to the next unconsumed token
   in the stabs string.  For example, given stabs "A:T4=s4a:1,0,32;;",
   in the stabs string.  For example, given stabs "A:T4=s4a:1,0,32;;",
   *PP will point to "4a:1,0,32;;".  */
   *PP will point to "4a:1,0,32;;".  */
 
 
static debug_type
static debug_type
parse_stab_struct_type (void *dhandle, struct stab_handle *info,
parse_stab_struct_type (void *dhandle, struct stab_handle *info,
                        const char *tagname, const char **pp,
                        const char *tagname, const char **pp,
                        bfd_boolean structp, const int *typenums)
                        bfd_boolean structp, const int *typenums)
{
{
  bfd_vma size;
  bfd_vma size;
  debug_baseclass *baseclasses;
  debug_baseclass *baseclasses;
  debug_field *fields;
  debug_field *fields;
  bfd_boolean statics;
  bfd_boolean statics;
  debug_method *methods;
  debug_method *methods;
  debug_type vptrbase;
  debug_type vptrbase;
  bfd_boolean ownvptr;
  bfd_boolean ownvptr;
 
 
  /* Get the size.  */
  /* Get the size.  */
  size = parse_number (pp, (bfd_boolean *) NULL);
  size = parse_number (pp, (bfd_boolean *) NULL);
 
 
  /* Get the other information.  */
  /* Get the other information.  */
  if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses)
  if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses)
      || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics)
      || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics)
      || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods)
      || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods)
      || ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase,
      || ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase,
                                   &ownvptr))
                                   &ownvptr))
    return DEBUG_TYPE_NULL;
    return DEBUG_TYPE_NULL;
 
 
  if (! statics
  if (! statics
      && baseclasses == NULL
      && baseclasses == NULL
      && methods == NULL
      && methods == NULL
      && vptrbase == DEBUG_TYPE_NULL
      && vptrbase == DEBUG_TYPE_NULL
      && ! ownvptr)
      && ! ownvptr)
    return debug_make_struct_type (dhandle, structp, size, fields);
    return debug_make_struct_type (dhandle, structp, size, fields);
 
 
  return debug_make_object_type (dhandle, structp, size, fields, baseclasses,
  return debug_make_object_type (dhandle, structp, size, fields, baseclasses,
                                 methods, vptrbase, ownvptr);
                                 methods, vptrbase, ownvptr);
}
}
 
 
/* The stabs for C++ derived classes contain baseclass information which
/* The stabs for C++ derived classes contain baseclass information which
   is marked by a '!' character after the total size.  This function is
   is marked by a '!' character after the total size.  This function is
   called when we encounter the baseclass marker, and slurps up all the
   called when we encounter the baseclass marker, and slurps up all the
   baseclass information.
   baseclass information.
 
 
   Immediately following the '!' marker is the number of base classes that
   Immediately following the '!' marker is the number of base classes that
   the class is derived from, followed by information for each base class.
   the class is derived from, followed by information for each base class.
   For each base class, there are two visibility specifiers, a bit offset
   For each base class, there are two visibility specifiers, a bit offset
   to the base class information within the derived class, a reference to
   to the base class information within the derived class, a reference to
   the type for the base class, and a terminating semicolon.
   the type for the base class, and a terminating semicolon.
 
 
   A typical example, with two base classes, would be "!2,020,19;0264,21;".
   A typical example, with two base classes, would be "!2,020,19;0264,21;".
                                                       ^^ ^ ^ ^  ^ ^  ^
                                                       ^^ ^ ^ ^  ^ ^  ^
        Baseclass information marker __________________|| | | |  | |  |
        Baseclass information marker __________________|| | | |  | |  |
        Number of baseclasses __________________________| | | |  | |  |
        Number of baseclasses __________________________| | | |  | |  |
        Visibility specifiers (2) ________________________| | |  | |  |
        Visibility specifiers (2) ________________________| | |  | |  |
        Offset in bits from start of class _________________| |  | |  |
        Offset in bits from start of class _________________| |  | |  |
        Type number for base class ___________________________|  | |  |
        Type number for base class ___________________________|  | |  |
        Visibility specifiers (2) _______________________________| |  |
        Visibility specifiers (2) _______________________________| |  |
        Offset in bits from start of class ________________________|  |
        Offset in bits from start of class ________________________|  |
        Type number of base class ____________________________________|
        Type number of base class ____________________________________|
 
 
  Return TRUE for success, FALSE for failure.  */
  Return TRUE for success, FALSE for failure.  */
 
 
static bfd_boolean
static bfd_boolean
parse_stab_baseclasses (void *dhandle, struct stab_handle *info,
parse_stab_baseclasses (void *dhandle, struct stab_handle *info,
                        const char **pp, debug_baseclass **retp)
                        const char **pp, debug_baseclass **retp)
{
{
  const char *orig;
  const char *orig;
  unsigned int c, i;
  unsigned int c, i;
  debug_baseclass *classes;
  debug_baseclass *classes;
 
 
  *retp = NULL;
  *retp = NULL;
 
 
  orig = *pp;
  orig = *pp;
 
 
  if (**pp != '!')
  if (**pp != '!')
    {
    {
      /* No base classes.  */
      /* No base classes.  */
      return TRUE;
      return TRUE;
    }
    }
  ++*pp;
  ++*pp;
 
 
  c = (unsigned int) parse_number (pp, (bfd_boolean *) NULL);
  c = (unsigned int) parse_number (pp, (bfd_boolean *) NULL);
 
 
  if (**pp != ',')
  if (**pp != ',')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return FALSE;
      return FALSE;
    }
    }
  ++*pp;
  ++*pp;
 
 
  classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp));
  classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp));
 
 
  for (i = 0; i < c; i++)
  for (i = 0; i < c; i++)
    {
    {
      bfd_boolean is_virtual;
      bfd_boolean is_virtual;
      enum debug_visibility visibility;
      enum debug_visibility visibility;
      bfd_vma bitpos;
      bfd_vma bitpos;
      debug_type type;
      debug_type type;
 
 
      switch (**pp)
      switch (**pp)
        {
        {
        case '0':
        case '0':
          is_virtual = FALSE;
          is_virtual = FALSE;
          break;
          break;
        case '1':
        case '1':
          is_virtual = TRUE;
          is_virtual = TRUE;
          break;
          break;
        default:
        default:
          warn_stab (orig, _("unknown virtual character for baseclass"));
          warn_stab (orig, _("unknown virtual character for baseclass"));
          is_virtual = FALSE;
          is_virtual = FALSE;
          break;
          break;
        }
        }
      ++*pp;
      ++*pp;
 
 
      switch (**pp)
      switch (**pp)
        {
        {
        case '0':
        case '0':
          visibility = DEBUG_VISIBILITY_PRIVATE;
          visibility = DEBUG_VISIBILITY_PRIVATE;
          break;
          break;
        case '1':
        case '1':
          visibility = DEBUG_VISIBILITY_PROTECTED;
          visibility = DEBUG_VISIBILITY_PROTECTED;
          break;
          break;
        case '2':
        case '2':
          visibility = DEBUG_VISIBILITY_PUBLIC;
          visibility = DEBUG_VISIBILITY_PUBLIC;
          break;
          break;
        default:
        default:
          warn_stab (orig, _("unknown visibility character for baseclass"));
          warn_stab (orig, _("unknown visibility character for baseclass"));
          visibility = DEBUG_VISIBILITY_PUBLIC;
          visibility = DEBUG_VISIBILITY_PUBLIC;
          break;
          break;
        }
        }
      ++*pp;
      ++*pp;
 
 
      /* The remaining value is the bit offset of the portion of the
      /* The remaining value is the bit offset of the portion of the
         object corresponding to this baseclass.  Always zero in the
         object corresponding to this baseclass.  Always zero in the
         absence of multiple inheritance.  */
         absence of multiple inheritance.  */
      bitpos = parse_number (pp, (bfd_boolean *) NULL);
      bitpos = parse_number (pp, (bfd_boolean *) NULL);
      if (**pp != ',')
      if (**pp != ',')
        {
        {
          bad_stab (orig);
          bad_stab (orig);
          return FALSE;
          return FALSE;
        }
        }
      ++*pp;
      ++*pp;
 
 
      type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
      type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
                              (debug_type **) NULL);
                              (debug_type **) NULL);
      if (type == DEBUG_TYPE_NULL)
      if (type == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
 
 
      classes[i] = debug_make_baseclass (dhandle, type, bitpos, is_virtual,
      classes[i] = debug_make_baseclass (dhandle, type, bitpos, is_virtual,
                                         visibility);
                                         visibility);
      if (classes[i] == DEBUG_BASECLASS_NULL)
      if (classes[i] == DEBUG_BASECLASS_NULL)
        return FALSE;
        return FALSE;
 
 
      if (**pp != ';')
      if (**pp != ';')
        return FALSE;
        return FALSE;
      ++*pp;
      ++*pp;
    }
    }
 
 
  classes[i] = DEBUG_BASECLASS_NULL;
  classes[i] = DEBUG_BASECLASS_NULL;
 
 
  *retp = classes;
  *retp = classes;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Read struct or class data fields.  They have the form:
/* Read struct or class data fields.  They have the form:
 
 
        NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
        NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ;
 
 
   At the end, we see a semicolon instead of a field.
   At the end, we see a semicolon instead of a field.
 
 
   In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
   In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for
   a static field.
   a static field.
 
 
   The optional VISIBILITY is one of:
   The optional VISIBILITY is one of:
 
 
        '/0'    (VISIBILITY_PRIVATE)
        '/0'    (VISIBILITY_PRIVATE)
        '/1'    (VISIBILITY_PROTECTED)
        '/1'    (VISIBILITY_PROTECTED)
        '/2'    (VISIBILITY_PUBLIC)
        '/2'    (VISIBILITY_PUBLIC)
        '/9'    (VISIBILITY_IGNORE)
        '/9'    (VISIBILITY_IGNORE)
 
 
   or nothing, for C style fields with public visibility.
   or nothing, for C style fields with public visibility.
 
 
   Returns 1 for success, 0 for failure.  */
   Returns 1 for success, 0 for failure.  */
 
 
static bfd_boolean
static bfd_boolean
parse_stab_struct_fields (void *dhandle, struct stab_handle *info,
parse_stab_struct_fields (void *dhandle, struct stab_handle *info,
                          const char **pp, debug_field **retp,
                          const char **pp, debug_field **retp,
                          bfd_boolean *staticsp)
                          bfd_boolean *staticsp)
{
{
  const char *orig;
  const char *orig;
  const char *p;
  const char *p;
  debug_field *fields;
  debug_field *fields;
  unsigned int c;
  unsigned int c;
  unsigned int alloc;
  unsigned int alloc;
 
 
  *retp = NULL;
  *retp = NULL;
  *staticsp = FALSE;
  *staticsp = FALSE;
 
 
  orig = *pp;
  orig = *pp;
 
 
  c = 0;
  c = 0;
  alloc = 10;
  alloc = 10;
  fields = (debug_field *) xmalloc (alloc * sizeof *fields);
  fields = (debug_field *) xmalloc (alloc * sizeof *fields);
  while (**pp != ';')
  while (**pp != ';')
    {
    {
      /* FIXME: gdb checks os9k_stabs here.  */
      /* FIXME: gdb checks os9k_stabs here.  */
 
 
      p = *pp;
      p = *pp;
 
 
      /* Add 1 to c to leave room for NULL pointer at end.  */
      /* Add 1 to c to leave room for NULL pointer at end.  */
      if (c + 1 >= alloc)
      if (c + 1 >= alloc)
        {
        {
          alloc += 10;
          alloc += 10;
          fields = ((debug_field *)
          fields = ((debug_field *)
                    xrealloc (fields, alloc * sizeof *fields));
                    xrealloc (fields, alloc * sizeof *fields));
        }
        }
 
 
      /* If it starts with CPLUS_MARKER it is a special abbreviation,
      /* If it starts with CPLUS_MARKER it is a special abbreviation,
         unless the CPLUS_MARKER is followed by an underscore, in
         unless the CPLUS_MARKER is followed by an underscore, in
         which case it is just the name of an anonymous type, which we
         which case it is just the name of an anonymous type, which we
         should handle like any other type name.  We accept either '$'
         should handle like any other type name.  We accept either '$'
         or '.', because a field name can never contain one of these
         or '.', because a field name can never contain one of these
         characters except as a CPLUS_MARKER.  */
         characters except as a CPLUS_MARKER.  */
 
 
      if ((*p == '$' || *p == '.') && p[1] != '_')
      if ((*p == '$' || *p == '.') && p[1] != '_')
        {
        {
          ++*pp;
          ++*pp;
          if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c))
          if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c))
            return FALSE;
            return FALSE;
          ++c;
          ++c;
          continue;
          continue;
        }
        }
 
 
      /* Look for the ':' that separates the field name from the field
      /* Look for the ':' that separates the field name from the field
         values.  Data members are delimited by a single ':', while member
         values.  Data members are delimited by a single ':', while member
         functions are delimited by a pair of ':'s.  When we hit the member
         functions are delimited by a pair of ':'s.  When we hit the member
         functions (if any), terminate scan loop and return.  */
         functions (if any), terminate scan loop and return.  */
 
 
      p = strchr (p, ':');
      p = strchr (p, ':');
      if (p == NULL)
      if (p == NULL)
        {
        {
          bad_stab (orig);
          bad_stab (orig);
          return FALSE;
          return FALSE;
        }
        }
 
 
      if (p[1] == ':')
      if (p[1] == ':')
        break;
        break;
 
 
      if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c,
      if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c,
                                         staticsp))
                                         staticsp))
        return FALSE;
        return FALSE;
 
 
      ++c;
      ++c;
    }
    }
 
 
  fields[c] = DEBUG_FIELD_NULL;
  fields[c] = DEBUG_FIELD_NULL;
 
 
  *retp = fields;
  *retp = fields;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Special GNU C++ name.  */
/* Special GNU C++ name.  */
 
 
static bfd_boolean
static bfd_boolean
parse_stab_cpp_abbrev (void *dhandle, struct stab_handle *info,
parse_stab_cpp_abbrev (void *dhandle, struct stab_handle *info,
                       const char **pp, debug_field *retp)
                       const char **pp, debug_field *retp)
{
{
  const char *orig;
  const char *orig;
  int cpp_abbrev;
  int cpp_abbrev;
  debug_type context;
  debug_type context;
  const char *name;
  const char *name;
  const char *type_name;
  const char *type_name;
  debug_type type;
  debug_type type;
  bfd_vma bitpos;
  bfd_vma bitpos;
 
 
  *retp = DEBUG_FIELD_NULL;
  *retp = DEBUG_FIELD_NULL;
 
 
  orig = *pp;
  orig = *pp;
 
 
  if (**pp != 'v')
  if (**pp != 'v')
    {
    {
      bad_stab (*pp);
      bad_stab (*pp);
      return FALSE;
      return FALSE;
    }
    }
  ++*pp;
  ++*pp;
 
 
  cpp_abbrev = **pp;
  cpp_abbrev = **pp;
  ++*pp;
  ++*pp;
 
 
  /* At this point, *pp points to something like "22:23=*22...", where
  /* At this point, *pp points to something like "22:23=*22...", where
     the type number before the ':' is the "context" and everything
     the type number before the ':' is the "context" and everything
     after is a regular type definition.  Lookup the type, find it's
     after is a regular type definition.  Lookup the type, find it's
     name, and construct the field name.  */
     name, and construct the field name.  */
 
 
  context = parse_stab_type (dhandle, info, (const char *) NULL, pp,
  context = parse_stab_type (dhandle, info, (const char *) NULL, pp,
                             (debug_type **) NULL);
                             (debug_type **) NULL);
  if (context == DEBUG_TYPE_NULL)
  if (context == DEBUG_TYPE_NULL)
    return FALSE;
    return FALSE;
 
 
  switch (cpp_abbrev)
  switch (cpp_abbrev)
    {
    {
    case 'f':
    case 'f':
      /* $vf -- a virtual function table pointer.  */
      /* $vf -- a virtual function table pointer.  */
      name = "_vptr$";
      name = "_vptr$";
      break;
      break;
    case 'b':
    case 'b':
      /* $vb -- a virtual bsomethingorother */
      /* $vb -- a virtual bsomethingorother */
      type_name = debug_get_type_name (dhandle, context);
      type_name = debug_get_type_name (dhandle, context);
      if (type_name == NULL)
      if (type_name == NULL)
        {
        {
          warn_stab (orig, _("unnamed $vb type"));
          warn_stab (orig, _("unnamed $vb type"));
          type_name = "FOO";
          type_name = "FOO";
        }
        }
      name = concat ("_vb$", type_name, (const char *) NULL);
      name = concat ("_vb$", type_name, (const char *) NULL);
      break;
      break;
    default:
    default:
      warn_stab (orig, _("unrecognized C++ abbreviation"));
      warn_stab (orig, _("unrecognized C++ abbreviation"));
      name = "INVALID_CPLUSPLUS_ABBREV";
      name = "INVALID_CPLUSPLUS_ABBREV";
      break;
      break;
    }
    }
 
 
  if (**pp != ':')
  if (**pp != ':')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return FALSE;
      return FALSE;
    }
    }
  ++*pp;
  ++*pp;
 
 
  type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
  type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
                          (debug_type **) NULL);
                          (debug_type **) NULL);
  if (**pp != ',')
  if (**pp != ',')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return FALSE;
      return FALSE;
    }
    }
  ++*pp;
  ++*pp;
 
 
  bitpos = parse_number (pp, (bfd_boolean *) NULL);
  bitpos = parse_number (pp, (bfd_boolean *) NULL);
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return FALSE;
      return FALSE;
    }
    }
  ++*pp;
  ++*pp;
 
 
  *retp = debug_make_field (dhandle, name, type, bitpos, 0,
  *retp = debug_make_field (dhandle, name, type, bitpos, 0,
                            DEBUG_VISIBILITY_PRIVATE);
                            DEBUG_VISIBILITY_PRIVATE);
  if (*retp == DEBUG_FIELD_NULL)
  if (*retp == DEBUG_FIELD_NULL)
    return FALSE;
    return FALSE;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Parse a single field in a struct or union.  */
/* Parse a single field in a struct or union.  */
 
 
static bfd_boolean
static bfd_boolean
parse_stab_one_struct_field (void *dhandle, struct stab_handle *info,
parse_stab_one_struct_field (void *dhandle, struct stab_handle *info,
                             const char **pp, const char *p,
                             const char **pp, const char *p,
                             debug_field *retp, bfd_boolean *staticsp)
                             debug_field *retp, bfd_boolean *staticsp)
{
{
  const char *orig;
  const char *orig;
  char *name;
  char *name;
  enum debug_visibility visibility;
  enum debug_visibility visibility;
  debug_type type;
  debug_type type;
  bfd_vma bitpos;
  bfd_vma bitpos;
  bfd_vma bitsize;
  bfd_vma bitsize;
 
 
  orig = *pp;
  orig = *pp;
 
 
  /* FIXME: gdb checks ARM_DEMANGLING here.  */
  /* FIXME: gdb checks ARM_DEMANGLING here.  */
 
 
  name = savestring (*pp, p - *pp);
  name = savestring (*pp, p - *pp);
 
 
  *pp = p + 1;
  *pp = p + 1;
 
 
  if (**pp != '/')
  if (**pp != '/')
    visibility = DEBUG_VISIBILITY_PUBLIC;
    visibility = DEBUG_VISIBILITY_PUBLIC;
  else
  else
    {
    {
      ++*pp;
      ++*pp;
      switch (**pp)
      switch (**pp)
        {
        {
        case '0':
        case '0':
          visibility = DEBUG_VISIBILITY_PRIVATE;
          visibility = DEBUG_VISIBILITY_PRIVATE;
          break;
          break;
        case '1':
        case '1':
          visibility = DEBUG_VISIBILITY_PROTECTED;
          visibility = DEBUG_VISIBILITY_PROTECTED;
          break;
          break;
        case '2':
        case '2':
          visibility = DEBUG_VISIBILITY_PUBLIC;
          visibility = DEBUG_VISIBILITY_PUBLIC;
          break;
          break;
        default:
        default:
          warn_stab (orig, _("unknown visibility character for field"));
          warn_stab (orig, _("unknown visibility character for field"));
          visibility = DEBUG_VISIBILITY_PUBLIC;
          visibility = DEBUG_VISIBILITY_PUBLIC;
          break;
          break;
        }
        }
      ++*pp;
      ++*pp;
    }
    }
 
 
  type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
  type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
                          (debug_type **) NULL);
                          (debug_type **) NULL);
  if (type == DEBUG_TYPE_NULL)
  if (type == DEBUG_TYPE_NULL)
    return FALSE;
    return FALSE;
 
 
  if (**pp == ':')
  if (**pp == ':')
    {
    {
      char *varname;
      char *varname;
 
 
      /* This is a static class member.  */
      /* This is a static class member.  */
      ++*pp;
      ++*pp;
      p = strchr (*pp, ';');
      p = strchr (*pp, ';');
      if (p == NULL)
      if (p == NULL)
        {
        {
          bad_stab (orig);
          bad_stab (orig);
          return FALSE;
          return FALSE;
        }
        }
 
 
      varname = savestring (*pp, p - *pp);
      varname = savestring (*pp, p - *pp);
 
 
      *pp = p + 1;
      *pp = p + 1;
 
 
      *retp = debug_make_static_member (dhandle, name, type, varname,
      *retp = debug_make_static_member (dhandle, name, type, varname,
                                        visibility);
                                        visibility);
      *staticsp = TRUE;
      *staticsp = TRUE;
 
 
      return TRUE;
      return TRUE;
    }
    }
 
 
  if (**pp != ',')
  if (**pp != ',')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return FALSE;
      return FALSE;
    }
    }
  ++*pp;
  ++*pp;
 
 
  bitpos = parse_number (pp, (bfd_boolean *) NULL);
  bitpos = parse_number (pp, (bfd_boolean *) NULL);
  if (**pp != ',')
  if (**pp != ',')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return FALSE;
      return FALSE;
    }
    }
  ++*pp;
  ++*pp;
 
 
  bitsize = parse_number (pp, (bfd_boolean *) NULL);
  bitsize = parse_number (pp, (bfd_boolean *) NULL);
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return FALSE;
      return FALSE;
    }
    }
  ++*pp;
  ++*pp;
 
 
  if (bitpos == 0 && bitsize == 0)
  if (bitpos == 0 && bitsize == 0)
    {
    {
      /* This can happen in two cases: (1) at least for gcc 2.4.5 or
      /* This can happen in two cases: (1) at least for gcc 2.4.5 or
         so, it is a field which has been optimized out.  The correct
         so, it is a field which has been optimized out.  The correct
         stab for this case is to use VISIBILITY_IGNORE, but that is a
         stab for this case is to use VISIBILITY_IGNORE, but that is a
         recent invention.  (2) It is a 0-size array.  For example
         recent invention.  (2) It is a 0-size array.  For example
         union { int num; char str[0]; } foo.  Printing "<no value>"
         union { int num; char str[0]; } foo.  Printing "<no value>"
         for str in "p foo" is OK, since foo.str (and thus foo.str[3])
         for str in "p foo" is OK, since foo.str (and thus foo.str[3])
         will continue to work, and a 0-size array as a whole doesn't
         will continue to work, and a 0-size array as a whole doesn't
         have any contents to print.
         have any contents to print.
 
 
         I suspect this probably could also happen with gcc -gstabs
         I suspect this probably could also happen with gcc -gstabs
         (not -gstabs+) for static fields, and perhaps other C++
         (not -gstabs+) for static fields, and perhaps other C++
         extensions.  Hopefully few people use -gstabs with gdb, since
         extensions.  Hopefully few people use -gstabs with gdb, since
         it is intended for dbx compatibility.  */
         it is intended for dbx compatibility.  */
      visibility = DEBUG_VISIBILITY_IGNORE;
      visibility = DEBUG_VISIBILITY_IGNORE;
    }
    }
 
 
  /* FIXME: gdb does some stuff here to mark fields as unpacked.  */
  /* FIXME: gdb does some stuff here to mark fields as unpacked.  */
 
 
  *retp = debug_make_field (dhandle, name, type, bitpos, bitsize, visibility);
  *retp = debug_make_field (dhandle, name, type, bitpos, bitsize, visibility);
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Read member function stabs info for C++ classes.  The form of each member
/* Read member function stabs info for C++ classes.  The form of each member
   function data is:
   function data is:
 
 
        NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ;
        NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ;
 
 
   An example with two member functions is:
   An example with two member functions is:
 
 
        afunc1::20=##15;:i;2A.;afunc2::20:i;2A.;
        afunc1::20=##15;:i;2A.;afunc2::20:i;2A.;
 
 
   For the case of overloaded operators, the format is op$::*.funcs, where
   For the case of overloaded operators, the format is op$::*.funcs, where
   $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator
   $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator
   name (such as `+=') and `.' marks the end of the operator name.  */
   name (such as `+=') and `.' marks the end of the operator name.  */
 
 
static bfd_boolean
static bfd_boolean
parse_stab_members (void *dhandle, struct stab_handle *info,
parse_stab_members (void *dhandle, struct stab_handle *info,
                    const char *tagname, const char **pp,
                    const char *tagname, const char **pp,
                    const int *typenums, debug_method **retp)
                    const int *typenums, debug_method **retp)
{
{
  const char *orig;
  const char *orig;
  debug_method *methods;
  debug_method *methods;
  unsigned int c;
  unsigned int c;
  unsigned int alloc;
  unsigned int alloc;
 
 
  *retp = NULL;
  *retp = NULL;
 
 
  orig = *pp;
  orig = *pp;
 
 
  alloc = 0;
  alloc = 0;
  methods = NULL;
  methods = NULL;
  c = 0;
  c = 0;
 
 
  while (**pp != ';')
  while (**pp != ';')
    {
    {
      const char *p;
      const char *p;
      char *name;
      char *name;
      debug_method_variant *variants;
      debug_method_variant *variants;
      unsigned int cvars;
      unsigned int cvars;
      unsigned int allocvars;
      unsigned int allocvars;
      debug_type look_ahead_type;
      debug_type look_ahead_type;
 
 
      p = strchr (*pp, ':');
      p = strchr (*pp, ':');
      if (p == NULL || p[1] != ':')
      if (p == NULL || p[1] != ':')
        break;
        break;
 
 
      /* FIXME: Some systems use something other than '$' here.  */
      /* FIXME: Some systems use something other than '$' here.  */
      if ((*pp)[0] != 'o' || (*pp)[1] != 'p' || (*pp)[2] != '$')
      if ((*pp)[0] != 'o' || (*pp)[1] != 'p' || (*pp)[2] != '$')
        {
        {
          name = savestring (*pp, p - *pp);
          name = savestring (*pp, p - *pp);
          *pp = p + 2;
          *pp = p + 2;
        }
        }
      else
      else
        {
        {
          /* This is a completely weird case.  In order to stuff in the
          /* This is a completely weird case.  In order to stuff in the
             names that might contain colons (the usual name delimiter),
             names that might contain colons (the usual name delimiter),
             Mike Tiemann defined a different name format which is
             Mike Tiemann defined a different name format which is
             signalled if the identifier is "op$".  In that case, the
             signalled if the identifier is "op$".  In that case, the
             format is "op$::XXXX." where XXXX is the name.  This is
             format is "op$::XXXX." where XXXX is the name.  This is
             used for names like "+" or "=".  YUUUUUUUK!  FIXME!  */
             used for names like "+" or "=".  YUUUUUUUK!  FIXME!  */
          *pp = p + 2;
          *pp = p + 2;
          for (p = *pp; *p != '.' && *p != '\0'; p++)
          for (p = *pp; *p != '.' && *p != '\0'; p++)
            ;
            ;
          if (*p != '.')
          if (*p != '.')
            {
            {
              bad_stab (orig);
              bad_stab (orig);
              return FALSE;
              return FALSE;
            }
            }
          name = savestring (*pp, p - *pp);
          name = savestring (*pp, p - *pp);
          *pp = p + 1;
          *pp = p + 1;
        }
        }
 
 
      allocvars = 10;
      allocvars = 10;
      variants = ((debug_method_variant *)
      variants = ((debug_method_variant *)
                  xmalloc (allocvars * sizeof *variants));
                  xmalloc (allocvars * sizeof *variants));
      cvars = 0;
      cvars = 0;
 
 
      look_ahead_type = DEBUG_TYPE_NULL;
      look_ahead_type = DEBUG_TYPE_NULL;
 
 
      do
      do
        {
        {
          debug_type type;
          debug_type type;
          bfd_boolean stub;
          bfd_boolean stub;
          char *argtypes;
          char *argtypes;
          enum debug_visibility visibility;
          enum debug_visibility visibility;
          bfd_boolean constp, volatilep, staticp;
          bfd_boolean constp, volatilep, staticp;
          bfd_vma voffset;
          bfd_vma voffset;
          debug_type context;
          debug_type context;
          const char *physname;
          const char *physname;
          bfd_boolean varargs;
          bfd_boolean varargs;
 
 
          if (look_ahead_type != DEBUG_TYPE_NULL)
          if (look_ahead_type != DEBUG_TYPE_NULL)
            {
            {
              /* g++ version 1 kludge */
              /* g++ version 1 kludge */
              type = look_ahead_type;
              type = look_ahead_type;
              look_ahead_type = DEBUG_TYPE_NULL;
              look_ahead_type = DEBUG_TYPE_NULL;
            }
            }
          else
          else
            {
            {
              type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
              type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
                                      (debug_type **) NULL);
                                      (debug_type **) NULL);
              if (type == DEBUG_TYPE_NULL)
              if (type == DEBUG_TYPE_NULL)
                return FALSE;
                return FALSE;
              if (**pp != ':')
              if (**pp != ':')
                {
                {
                  bad_stab (orig);
                  bad_stab (orig);
                  return FALSE;
                  return FALSE;
                }
                }
            }
            }
 
 
          ++*pp;
          ++*pp;
          p = strchr (*pp, ';');
          p = strchr (*pp, ';');
          if (p == NULL)
          if (p == NULL)
            {
            {
              bad_stab (orig);
              bad_stab (orig);
              return FALSE;
              return FALSE;
            }
            }
 
 
          stub = FALSE;
          stub = FALSE;
          if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD
          if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD
              && debug_get_parameter_types (dhandle, type, &varargs) == NULL)
              && debug_get_parameter_types (dhandle, type, &varargs) == NULL)
            stub = TRUE;
            stub = TRUE;
 
 
          argtypes = savestring (*pp, p - *pp);
          argtypes = savestring (*pp, p - *pp);
          *pp = p + 1;
          *pp = p + 1;
 
 
          switch (**pp)
          switch (**pp)
            {
            {
            case '0':
            case '0':
              visibility = DEBUG_VISIBILITY_PRIVATE;
              visibility = DEBUG_VISIBILITY_PRIVATE;
              break;
              break;
            case '1':
            case '1':
              visibility = DEBUG_VISIBILITY_PROTECTED;
              visibility = DEBUG_VISIBILITY_PROTECTED;
              break;
              break;
            default:
            default:
              visibility = DEBUG_VISIBILITY_PUBLIC;
              visibility = DEBUG_VISIBILITY_PUBLIC;
              break;
              break;
            }
            }
          ++*pp;
          ++*pp;
 
 
          constp = FALSE;
          constp = FALSE;
          volatilep = FALSE;
          volatilep = FALSE;
          switch (**pp)
          switch (**pp)
            {
            {
            case 'A':
            case 'A':
              /* Normal function.  */
              /* Normal function.  */
              ++*pp;
              ++*pp;
              break;
              break;
            case 'B':
            case 'B':
              /* const member function.  */
              /* const member function.  */
              constp = TRUE;
              constp = TRUE;
              ++*pp;
              ++*pp;
              break;
              break;
            case 'C':
            case 'C':
              /* volatile member function.  */
              /* volatile member function.  */
              volatilep = TRUE;
              volatilep = TRUE;
              ++*pp;
              ++*pp;
              break;
              break;
            case 'D':
            case 'D':
              /* const volatile member function.  */
              /* const volatile member function.  */
              constp = TRUE;
              constp = TRUE;
              volatilep = TRUE;
              volatilep = TRUE;
              ++*pp;
              ++*pp;
              break;
              break;
            case '*':
            case '*':
            case '?':
            case '?':
            case '.':
            case '.':
              /* File compiled with g++ version 1; no information.  */
              /* File compiled with g++ version 1; no information.  */
              break;
              break;
            default:
            default:
              warn_stab (orig, _("const/volatile indicator missing"));
              warn_stab (orig, _("const/volatile indicator missing"));
              break;
              break;
            }
            }
 
 
          staticp = FALSE;
          staticp = FALSE;
          switch (**pp)
          switch (**pp)
            {
            {
            case '*':
            case '*':
              /* virtual member function, followed by index.  The sign
              /* virtual member function, followed by index.  The sign
                 bit is supposedly set to distinguish
                 bit is supposedly set to distinguish
                 pointers-to-methods from virtual function indicies.  */
                 pointers-to-methods from virtual function indicies.  */
              ++*pp;
              ++*pp;
              voffset = parse_number (pp, (bfd_boolean *) NULL);
              voffset = parse_number (pp, (bfd_boolean *) NULL);
              if (**pp != ';')
              if (**pp != ';')
                {
                {
                  bad_stab (orig);
                  bad_stab (orig);
                  return FALSE;
                  return FALSE;
                }
                }
              ++*pp;
              ++*pp;
              voffset &= 0x7fffffff;
              voffset &= 0x7fffffff;
 
 
              if (**pp == ';' || *pp == '\0')
              if (**pp == ';' || *pp == '\0')
                {
                {
                  /* Must be g++ version 1.  */
                  /* Must be g++ version 1.  */
                  context = DEBUG_TYPE_NULL;
                  context = DEBUG_TYPE_NULL;
                }
                }
              else
              else
                {
                {
                  /* Figure out from whence this virtual function
                  /* Figure out from whence this virtual function
                     came.  It may belong to virtual function table of
                     came.  It may belong to virtual function table of
                     one of its baseclasses.  */
                     one of its baseclasses.  */
                  look_ahead_type = parse_stab_type (dhandle, info,
                  look_ahead_type = parse_stab_type (dhandle, info,
                                                     (const char *) NULL,
                                                     (const char *) NULL,
                                                     pp,
                                                     pp,
                                                     (debug_type **) NULL);
                                                     (debug_type **) NULL);
                  if (**pp == ':')
                  if (**pp == ':')
                    {
                    {
                      /* g++ version 1 overloaded methods.  */
                      /* g++ version 1 overloaded methods.  */
                      context = DEBUG_TYPE_NULL;
                      context = DEBUG_TYPE_NULL;
                    }
                    }
                  else
                  else
                    {
                    {
                      context = look_ahead_type;
                      context = look_ahead_type;
                      look_ahead_type = DEBUG_TYPE_NULL;
                      look_ahead_type = DEBUG_TYPE_NULL;
                      if (**pp != ';')
                      if (**pp != ';')
                        {
                        {
                          bad_stab (orig);
                          bad_stab (orig);
                          return FALSE;
                          return FALSE;
                        }
                        }
                      ++*pp;
                      ++*pp;
                    }
                    }
                }
                }
              break;
              break;
 
 
            case '?':
            case '?':
              /* static member function.  */
              /* static member function.  */
              ++*pp;
              ++*pp;
              staticp = TRUE;
              staticp = TRUE;
              voffset = 0;
              voffset = 0;
              context = DEBUG_TYPE_NULL;
              context = DEBUG_TYPE_NULL;
              if (strncmp (argtypes, name, strlen (name)) != 0)
              if (strncmp (argtypes, name, strlen (name)) != 0)
                stub = TRUE;
                stub = TRUE;
              break;
              break;
 
 
            default:
            default:
              warn_stab (orig, "member function type missing");
              warn_stab (orig, "member function type missing");
              voffset = 0;
              voffset = 0;
              context = DEBUG_TYPE_NULL;
              context = DEBUG_TYPE_NULL;
              break;
              break;
 
 
            case '.':
            case '.':
              ++*pp;
              ++*pp;
              voffset = 0;
              voffset = 0;
              context = DEBUG_TYPE_NULL;
              context = DEBUG_TYPE_NULL;
              break;
              break;
            }
            }
 
 
          /* If the type is not a stub, then the argtypes string is
          /* If the type is not a stub, then the argtypes string is
             the physical name of the function.  Otherwise the
             the physical name of the function.  Otherwise the
             argtypes string is the mangled form of the argument
             argtypes string is the mangled form of the argument
             types, and the full type and the physical name must be
             types, and the full type and the physical name must be
             extracted from them.  */
             extracted from them.  */
          if (! stub)
          if (! stub)
            physname = argtypes;
            physname = argtypes;
          else
          else
            {
            {
              debug_type class_type, return_type;
              debug_type class_type, return_type;
 
 
              class_type = stab_find_type (dhandle, info, typenums);
              class_type = stab_find_type (dhandle, info, typenums);
              if (class_type == DEBUG_TYPE_NULL)
              if (class_type == DEBUG_TYPE_NULL)
                return FALSE;
                return FALSE;
              return_type = debug_get_return_type (dhandle, type);
              return_type = debug_get_return_type (dhandle, type);
              if (return_type == DEBUG_TYPE_NULL)
              if (return_type == DEBUG_TYPE_NULL)
                {
                {
                  bad_stab (orig);
                  bad_stab (orig);
                  return FALSE;
                  return FALSE;
                }
                }
              type = parse_stab_argtypes (dhandle, info, class_type, name,
              type = parse_stab_argtypes (dhandle, info, class_type, name,
                                          tagname, return_type, argtypes,
                                          tagname, return_type, argtypes,
                                          constp, volatilep, &physname);
                                          constp, volatilep, &physname);
              if (type == DEBUG_TYPE_NULL)
              if (type == DEBUG_TYPE_NULL)
                return FALSE;
                return FALSE;
            }
            }
 
 
          if (cvars + 1 >= allocvars)
          if (cvars + 1 >= allocvars)
            {
            {
              allocvars += 10;
              allocvars += 10;
              variants = ((debug_method_variant *)
              variants = ((debug_method_variant *)
                          xrealloc (variants,
                          xrealloc (variants,
                                    allocvars * sizeof *variants));
                                    allocvars * sizeof *variants));
            }
            }
 
 
          if (! staticp)
          if (! staticp)
            variants[cvars] = debug_make_method_variant (dhandle, physname,
            variants[cvars] = debug_make_method_variant (dhandle, physname,
                                                         type, visibility,
                                                         type, visibility,
                                                         constp, volatilep,
                                                         constp, volatilep,
                                                         voffset, context);
                                                         voffset, context);
          else
          else
            variants[cvars] = debug_make_static_method_variant (dhandle,
            variants[cvars] = debug_make_static_method_variant (dhandle,
                                                                physname,
                                                                physname,
                                                                type,
                                                                type,
                                                                visibility,
                                                                visibility,
                                                                constp,
                                                                constp,
                                                                volatilep);
                                                                volatilep);
          if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL)
          if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL)
            return FALSE;
            return FALSE;
 
 
          ++cvars;
          ++cvars;
        }
        }
      while (**pp != ';' && **pp != '\0');
      while (**pp != ';' && **pp != '\0');
 
 
      variants[cvars] = DEBUG_METHOD_VARIANT_NULL;
      variants[cvars] = DEBUG_METHOD_VARIANT_NULL;
 
 
      if (**pp != '\0')
      if (**pp != '\0')
        ++*pp;
        ++*pp;
 
 
      if (c + 1 >= alloc)
      if (c + 1 >= alloc)
        {
        {
          alloc += 10;
          alloc += 10;
          methods = ((debug_method *)
          methods = ((debug_method *)
                     xrealloc (methods, alloc * sizeof *methods));
                     xrealloc (methods, alloc * sizeof *methods));
        }
        }
 
 
      methods[c] = debug_make_method (dhandle, name, variants);
      methods[c] = debug_make_method (dhandle, name, variants);
 
 
      ++c;
      ++c;
    }
    }
 
 
  if (methods != NULL)
  if (methods != NULL)
    methods[c] = DEBUG_METHOD_NULL;
    methods[c] = DEBUG_METHOD_NULL;
 
 
  *retp = methods;
  *retp = methods;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Parse a string representing argument types for a method.  Stabs
/* Parse a string representing argument types for a method.  Stabs
   tries to save space by packing argument types into a mangled
   tries to save space by packing argument types into a mangled
   string.  This string should give us enough information to extract
   string.  This string should give us enough information to extract
   both argument types and the physical name of the function, given
   both argument types and the physical name of the function, given
   the tag name.  */
   the tag name.  */
 
 
static debug_type
static debug_type
parse_stab_argtypes (void *dhandle, struct stab_handle *info,
parse_stab_argtypes (void *dhandle, struct stab_handle *info,
                     debug_type class_type, const char *fieldname,
                     debug_type class_type, const char *fieldname,
                     const char *tagname, debug_type return_type,
                     const char *tagname, debug_type return_type,
                     const char *argtypes, bfd_boolean constp,
                     const char *argtypes, bfd_boolean constp,
                     bfd_boolean volatilep, const char **pphysname)
                     bfd_boolean volatilep, const char **pphysname)
{
{
  bfd_boolean is_full_physname_constructor;
  bfd_boolean is_full_physname_constructor;
  bfd_boolean is_constructor;
  bfd_boolean is_constructor;
  bfd_boolean is_destructor;
  bfd_boolean is_destructor;
  bfd_boolean is_v3;
  bfd_boolean is_v3;
  debug_type *args;
  debug_type *args;
  bfd_boolean varargs;
  bfd_boolean varargs;
  unsigned int physname_len = 0;
  unsigned int physname_len = 0;
 
 
  /* Constructors are sometimes handled specially.  */
  /* Constructors are sometimes handled specially.  */
  is_full_physname_constructor = ((argtypes[0] == '_'
  is_full_physname_constructor = ((argtypes[0] == '_'
                                   && argtypes[1] == '_'
                                   && argtypes[1] == '_'
                                   && (ISDIGIT (argtypes[2])
                                   && (ISDIGIT (argtypes[2])
                                       || argtypes[2] == 'Q'
                                       || argtypes[2] == 'Q'
                                       || argtypes[2] == 't'))
                                       || argtypes[2] == 't'))
                                  || CONST_STRNEQ (argtypes, "__ct"));
                                  || CONST_STRNEQ (argtypes, "__ct"));
 
 
  is_constructor = (is_full_physname_constructor
  is_constructor = (is_full_physname_constructor
                    || (tagname != NULL
                    || (tagname != NULL
                        && strcmp (fieldname, tagname) == 0));
                        && strcmp (fieldname, tagname) == 0));
  is_destructor = ((argtypes[0] == '_'
  is_destructor = ((argtypes[0] == '_'
                    && (argtypes[1] == '$' || argtypes[1] == '.')
                    && (argtypes[1] == '$' || argtypes[1] == '.')
                    && argtypes[2] == '_')
                    && argtypes[2] == '_')
                   || CONST_STRNEQ (argtypes, "__dt"));
                   || CONST_STRNEQ (argtypes, "__dt"));
  is_v3 = argtypes[0] == '_' && argtypes[1] == 'Z';
  is_v3 = argtypes[0] == '_' && argtypes[1] == 'Z';
 
 
  if (is_destructor || is_full_physname_constructor || is_v3)
  if (is_destructor || is_full_physname_constructor || is_v3)
    *pphysname = argtypes;
    *pphysname = argtypes;
  else
  else
    {
    {
      unsigned int len;
      unsigned int len;
      const char *const_prefix;
      const char *const_prefix;
      const char *volatile_prefix;
      const char *volatile_prefix;
      char buf[20];
      char buf[20];
      unsigned int mangled_name_len;
      unsigned int mangled_name_len;
      char *physname;
      char *physname;
 
 
      len = tagname == NULL ? 0 : strlen (tagname);
      len = tagname == NULL ? 0 : strlen (tagname);
      const_prefix = constp ? "C" : "";
      const_prefix = constp ? "C" : "";
      volatile_prefix = volatilep ? "V" : "";
      volatile_prefix = volatilep ? "V" : "";
 
 
      if (len == 0)
      if (len == 0)
        sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
        sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
      else if (tagname != NULL && strchr (tagname, '<') != NULL)
      else if (tagname != NULL && strchr (tagname, '<') != NULL)
        {
        {
          /* Template methods are fully mangled.  */
          /* Template methods are fully mangled.  */
          sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
          sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
          tagname = NULL;
          tagname = NULL;
          len = 0;
          len = 0;
        }
        }
      else
      else
        sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len);
        sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len);
 
 
      mangled_name_len = ((is_constructor ? 0 : strlen (fieldname))
      mangled_name_len = ((is_constructor ? 0 : strlen (fieldname))
                          + strlen (buf)
                          + strlen (buf)
                          + len
                          + len
                          + strlen (argtypes)
                          + strlen (argtypes)
                          + 1);
                          + 1);
 
 
      if (fieldname[0] == 'o'
      if (fieldname[0] == 'o'
          && fieldname[1] == 'p'
          && fieldname[1] == 'p'
          && (fieldname[2] == '$' || fieldname[2] == '.'))
          && (fieldname[2] == '$' || fieldname[2] == '.'))
        {
        {
          const char *opname;
          const char *opname;
 
 
          opname = cplus_mangle_opname (fieldname + 3, 0);
          opname = cplus_mangle_opname (fieldname + 3, 0);
          if (opname == NULL)
          if (opname == NULL)
            {
            {
              fprintf (stderr, _("No mangling for \"%s\"\n"), fieldname);
              fprintf (stderr, _("No mangling for \"%s\"\n"), fieldname);
              return DEBUG_TYPE_NULL;
              return DEBUG_TYPE_NULL;
            }
            }
          mangled_name_len += strlen (opname);
          mangled_name_len += strlen (opname);
          physname = (char *) xmalloc (mangled_name_len);
          physname = (char *) xmalloc (mangled_name_len);
          strncpy (physname, fieldname, 3);
          strncpy (physname, fieldname, 3);
          strcpy (physname + 3, opname);
          strcpy (physname + 3, opname);
        }
        }
      else
      else
        {
        {
          physname = (char *) xmalloc (mangled_name_len);
          physname = (char *) xmalloc (mangled_name_len);
          if (is_constructor)
          if (is_constructor)
            physname[0] = '\0';
            physname[0] = '\0';
          else
          else
            strcpy (physname, fieldname);
            strcpy (physname, fieldname);
        }
        }
 
 
      physname_len = strlen (physname);
      physname_len = strlen (physname);
      strcat (physname, buf);
      strcat (physname, buf);
      if (tagname != NULL)
      if (tagname != NULL)
        strcat (physname, tagname);
        strcat (physname, tagname);
      strcat (physname, argtypes);
      strcat (physname, argtypes);
 
 
      *pphysname = physname;
      *pphysname = physname;
    }
    }
 
 
  if (*argtypes == '\0' || is_destructor)
  if (*argtypes == '\0' || is_destructor)
    {
    {
      args = (debug_type *) xmalloc (sizeof *args);
      args = (debug_type *) xmalloc (sizeof *args);
      *args = NULL;
      *args = NULL;
      return debug_make_method_type (dhandle, return_type, class_type, args,
      return debug_make_method_type (dhandle, return_type, class_type, args,
                                     FALSE);
                                     FALSE);
    }
    }
 
 
  args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs, physname_len);
  args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs, physname_len);
  if (args == NULL)
  if (args == NULL)
    return DEBUG_TYPE_NULL;
    return DEBUG_TYPE_NULL;
 
 
  return debug_make_method_type (dhandle, return_type, class_type, args,
  return debug_make_method_type (dhandle, return_type, class_type, args,
                                 varargs);
                                 varargs);
}
}
 
 
/* The tail end of stabs for C++ classes that contain a virtual function
/* The tail end of stabs for C++ classes that contain a virtual function
   pointer contains a tilde, a %, and a type number.
   pointer contains a tilde, a %, and a type number.
   The type number refers to the base class (possibly this class itself) which
   The type number refers to the base class (possibly this class itself) which
   contains the vtable pointer for the current class.
   contains the vtable pointer for the current class.
 
 
   This function is called when we have parsed all the method declarations,
   This function is called when we have parsed all the method declarations,
   so we can look for the vptr base class info.  */
   so we can look for the vptr base class info.  */
 
 
static bfd_boolean
static bfd_boolean
parse_stab_tilde_field (void *dhandle, struct stab_handle *info,
parse_stab_tilde_field (void *dhandle, struct stab_handle *info,
                        const char **pp, const int *typenums,
                        const char **pp, const int *typenums,
                        debug_type *retvptrbase, bfd_boolean *retownvptr)
                        debug_type *retvptrbase, bfd_boolean *retownvptr)
{
{
  const char *orig;
  const char *orig;
  const char *hold;
  const char *hold;
  int vtypenums[2];
  int vtypenums[2];
 
 
  *retvptrbase = DEBUG_TYPE_NULL;
  *retvptrbase = DEBUG_TYPE_NULL;
  *retownvptr = FALSE;
  *retownvptr = FALSE;
 
 
  orig = *pp;
  orig = *pp;
 
 
  /* If we are positioned at a ';', then skip it.  */
  /* If we are positioned at a ';', then skip it.  */
  if (**pp == ';')
  if (**pp == ';')
    ++*pp;
    ++*pp;
 
 
  if (**pp != '~')
  if (**pp != '~')
    return TRUE;
    return TRUE;
 
 
  ++*pp;
  ++*pp;
 
 
  if (**pp == '=' || **pp == '+' || **pp == '-')
  if (**pp == '=' || **pp == '+' || **pp == '-')
    {
    {
      /* Obsolete flags that used to indicate the presence of
      /* Obsolete flags that used to indicate the presence of
         constructors and/or destructors.  */
         constructors and/or destructors.  */
      ++*pp;
      ++*pp;
    }
    }
 
 
  if (**pp != '%')
  if (**pp != '%')
    return TRUE;
    return TRUE;
 
 
  ++*pp;
  ++*pp;
 
 
  hold = *pp;
  hold = *pp;
 
 
  /* The next number is the type number of the base class (possibly
  /* The next number is the type number of the base class (possibly
     our own class) which supplies the vtable for this class.  */
     our own class) which supplies the vtable for this class.  */
  if (! parse_stab_type_number (pp, vtypenums))
  if (! parse_stab_type_number (pp, vtypenums))
    return FALSE;
    return FALSE;
 
 
  if (vtypenums[0] == typenums[0]
  if (vtypenums[0] == typenums[0]
      && vtypenums[1] == typenums[1])
      && vtypenums[1] == typenums[1])
    *retownvptr = TRUE;
    *retownvptr = TRUE;
  else
  else
    {
    {
      debug_type vtype;
      debug_type vtype;
      const char *p;
      const char *p;
 
 
      *pp = hold;
      *pp = hold;
 
 
      vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
      vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp,
                               (debug_type **) NULL);
                               (debug_type **) NULL);
      for (p = *pp; *p != ';' && *p != '\0'; p++)
      for (p = *pp; *p != ';' && *p != '\0'; p++)
        ;
        ;
      if (*p != ';')
      if (*p != ';')
        {
        {
          bad_stab (orig);
          bad_stab (orig);
          return FALSE;
          return FALSE;
        }
        }
 
 
      *retvptrbase = vtype;
      *retvptrbase = vtype;
 
 
      *pp = p + 1;
      *pp = p + 1;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Read a definition of an array type.  */
/* Read a definition of an array type.  */
 
 
static debug_type
static debug_type
parse_stab_array_type (void *dhandle, struct stab_handle *info,
parse_stab_array_type (void *dhandle, struct stab_handle *info,
                       const char **pp, bfd_boolean stringp)
                       const char **pp, bfd_boolean stringp)
{
{
  const char *orig;
  const char *orig;
  const char *p;
  const char *p;
  int typenums[2];
  int typenums[2];
  debug_type index_type;
  debug_type index_type;
  bfd_boolean adjustable;
  bfd_boolean adjustable;
  bfd_signed_vma lower, upper;
  bfd_signed_vma lower, upper;
  debug_type element_type;
  debug_type element_type;
 
 
  /* Format of an array type:
  /* Format of an array type:
     "ar<index type>;lower;upper;<array_contents_type>".
     "ar<index type>;lower;upper;<array_contents_type>".
     OS9000: "arlower,upper;<array_contents_type>".
     OS9000: "arlower,upper;<array_contents_type>".
 
 
     Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
     Fortran adjustable arrays use Adigits or Tdigits for lower or upper;
     for these, produce a type like float[][].  */
     for these, produce a type like float[][].  */
 
 
  orig = *pp;
  orig = *pp;
 
 
  /* FIXME: gdb checks os9k_stabs here.  */
  /* FIXME: gdb checks os9k_stabs here.  */
 
 
  /* If the index type is type 0, we take it as int.  */
  /* If the index type is type 0, we take it as int.  */
  p = *pp;
  p = *pp;
  if (! parse_stab_type_number (&p, typenums))
  if (! parse_stab_type_number (&p, typenums))
    return DEBUG_TYPE_NULL;
    return DEBUG_TYPE_NULL;
  if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=')
  if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=')
    {
    {
      index_type = debug_find_named_type (dhandle, "int");
      index_type = debug_find_named_type (dhandle, "int");
      if (index_type == DEBUG_TYPE_NULL)
      if (index_type == DEBUG_TYPE_NULL)
        {
        {
          index_type = debug_make_int_type (dhandle, 4, FALSE);
          index_type = debug_make_int_type (dhandle, 4, FALSE);
          if (index_type == DEBUG_TYPE_NULL)
          if (index_type == DEBUG_TYPE_NULL)
            return DEBUG_TYPE_NULL;
            return DEBUG_TYPE_NULL;
        }
        }
      *pp = p;
      *pp = p;
    }
    }
  else
  else
    {
    {
      index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
      index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
                                    (debug_type **) NULL);
                                    (debug_type **) NULL);
    }
    }
 
 
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
  ++*pp;
  ++*pp;
 
 
  adjustable = FALSE;
  adjustable = FALSE;
 
 
  if (! ISDIGIT (**pp) && **pp != '-')
  if (! ISDIGIT (**pp) && **pp != '-')
    {
    {
      ++*pp;
      ++*pp;
      adjustable = TRUE;
      adjustable = TRUE;
    }
    }
 
 
  lower = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
  lower = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
  ++*pp;
  ++*pp;
 
 
  if (! ISDIGIT (**pp) && **pp != '-')
  if (! ISDIGIT (**pp) && **pp != '-')
    {
    {
      ++*pp;
      ++*pp;
      adjustable = TRUE;
      adjustable = TRUE;
    }
    }
 
 
  upper = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
  upper = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL);
  if (**pp != ';')
  if (**pp != ';')
    {
    {
      bad_stab (orig);
      bad_stab (orig);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
  ++*pp;
  ++*pp;
 
 
  element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
  element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
                                  (debug_type **) NULL);
                                  (debug_type **) NULL);
  if (element_type == DEBUG_TYPE_NULL)
  if (element_type == DEBUG_TYPE_NULL)
    return DEBUG_TYPE_NULL;
    return DEBUG_TYPE_NULL;
 
 
  if (adjustable)
  if (adjustable)
    {
    {
      lower = 0;
      lower = 0;
      upper = -1;
      upper = -1;
    }
    }
 
 
  return debug_make_array_type (dhandle, element_type, index_type, lower,
  return debug_make_array_type (dhandle, element_type, index_type, lower,
                                upper, stringp);
                                upper, stringp);
}
}
 
 
/* This struct holds information about files we have seen using
/* This struct holds information about files we have seen using
   N_BINCL.  */
   N_BINCL.  */
 
 
struct bincl_file
struct bincl_file
{
{
  /* The next N_BINCL file.  */
  /* The next N_BINCL file.  */
  struct bincl_file *next;
  struct bincl_file *next;
  /* The next N_BINCL on the stack.  */
  /* The next N_BINCL on the stack.  */
  struct bincl_file *next_stack;
  struct bincl_file *next_stack;
  /* The file name.  */
  /* The file name.  */
  const char *name;
  const char *name;
  /* The hash value.  */
  /* The hash value.  */
  bfd_vma hash;
  bfd_vma hash;
  /* The file index.  */
  /* The file index.  */
  unsigned int file;
  unsigned int file;
  /* The list of types defined in this file.  */
  /* The list of types defined in this file.  */
  struct stab_types *file_types;
  struct stab_types *file_types;
};
};
 
 
/* Start a new N_BINCL file, pushing it onto the stack.  */
/* Start a new N_BINCL file, pushing it onto the stack.  */
 
 
static void
static void
push_bincl (struct stab_handle *info, const char *name, bfd_vma hash)
push_bincl (struct stab_handle *info, const char *name, bfd_vma hash)
{
{
  struct bincl_file *n;
  struct bincl_file *n;
 
 
  n = (struct bincl_file *) xmalloc (sizeof *n);
  n = (struct bincl_file *) xmalloc (sizeof *n);
  n->next = info->bincl_list;
  n->next = info->bincl_list;
  n->next_stack = info->bincl_stack;
  n->next_stack = info->bincl_stack;
  n->name = name;
  n->name = name;
  n->hash = hash;
  n->hash = hash;
  n->file = info->files;
  n->file = info->files;
  n->file_types = NULL;
  n->file_types = NULL;
  info->bincl_list = n;
  info->bincl_list = n;
  info->bincl_stack = n;
  info->bincl_stack = n;
 
 
  ++info->files;
  ++info->files;
  info->file_types = ((struct stab_types **)
  info->file_types = ((struct stab_types **)
                      xrealloc (info->file_types,
                      xrealloc (info->file_types,
                                (info->files
                                (info->files
                                 * sizeof *info->file_types)));
                                 * sizeof *info->file_types)));
  info->file_types[n->file] = NULL;
  info->file_types[n->file] = NULL;
}
}
 
 
/* Finish an N_BINCL file, at an N_EINCL, popping the name off the
/* Finish an N_BINCL file, at an N_EINCL, popping the name off the
   stack.  */
   stack.  */
 
 
static const char *
static const char *
pop_bincl (struct stab_handle *info)
pop_bincl (struct stab_handle *info)
{
{
  struct bincl_file *o;
  struct bincl_file *o;
 
 
  o = info->bincl_stack;
  o = info->bincl_stack;
  if (o == NULL)
  if (o == NULL)
    return info->main_filename;
    return info->main_filename;
  info->bincl_stack = o->next_stack;
  info->bincl_stack = o->next_stack;
 
 
  o->file_types = info->file_types[o->file];
  o->file_types = info->file_types[o->file];
 
 
  if (info->bincl_stack == NULL)
  if (info->bincl_stack == NULL)
    return info->main_filename;
    return info->main_filename;
  return info->bincl_stack->name;
  return info->bincl_stack->name;
}
}
 
 
/* Handle an N_EXCL: get the types from the corresponding N_BINCL.  */
/* Handle an N_EXCL: get the types from the corresponding N_BINCL.  */
 
 
static bfd_boolean
static bfd_boolean
find_excl (struct stab_handle *info, const char *name, bfd_vma hash)
find_excl (struct stab_handle *info, const char *name, bfd_vma hash)
{
{
  struct bincl_file *l;
  struct bincl_file *l;
 
 
  ++info->files;
  ++info->files;
  info->file_types = ((struct stab_types **)
  info->file_types = ((struct stab_types **)
                      xrealloc (info->file_types,
                      xrealloc (info->file_types,
                                (info->files
                                (info->files
                                 * sizeof *info->file_types)));
                                 * sizeof *info->file_types)));
 
 
  for (l = info->bincl_list; l != NULL; l = l->next)
  for (l = info->bincl_list; l != NULL; l = l->next)
    if (l->hash == hash && strcmp (l->name, name) == 0)
    if (l->hash == hash && strcmp (l->name, name) == 0)
      break;
      break;
  if (l == NULL)
  if (l == NULL)
    {
    {
      warn_stab (name, _("Undefined N_EXCL"));
      warn_stab (name, _("Undefined N_EXCL"));
      info->file_types[info->files - 1] = NULL;
      info->file_types[info->files - 1] = NULL;
      return TRUE;
      return TRUE;
    }
    }
 
 
  info->file_types[info->files - 1] = l->file_types;
  info->file_types[info->files - 1] = l->file_types;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Handle a variable definition.  gcc emits variable definitions for a
/* Handle a variable definition.  gcc emits variable definitions for a
   block before the N_LBRAC, so we must hold onto them until we see
   block before the N_LBRAC, so we must hold onto them until we see
   it.  The SunPRO compiler emits variable definitions after the
   it.  The SunPRO compiler emits variable definitions after the
   N_LBRAC, so we can call debug_record_variable immediately.  */
   N_LBRAC, so we can call debug_record_variable immediately.  */
 
 
static bfd_boolean
static bfd_boolean
stab_record_variable (void *dhandle, struct stab_handle *info,
stab_record_variable (void *dhandle, struct stab_handle *info,
                      const char *name, debug_type type,
                      const char *name, debug_type type,
                      enum debug_var_kind kind, bfd_vma val)
                      enum debug_var_kind kind, bfd_vma val)
{
{
  struct stab_pending_var *v;
  struct stab_pending_var *v;
 
 
  if ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC)
  if ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC)
      || ! info->within_function
      || ! info->within_function
      || (info->gcc_compiled == 0 && info->n_opt_found))
      || (info->gcc_compiled == 0 && info->n_opt_found))
    return debug_record_variable (dhandle, name, type, kind, val);
    return debug_record_variable (dhandle, name, type, kind, val);
 
 
  v = (struct stab_pending_var *) xmalloc (sizeof *v);
  v = (struct stab_pending_var *) xmalloc (sizeof *v);
  memset (v, 0, sizeof *v);
  memset (v, 0, sizeof *v);
 
 
  v->next = info->pending;
  v->next = info->pending;
  v->name = name;
  v->name = name;
  v->type = type;
  v->type = type;
  v->kind = kind;
  v->kind = kind;
  v->val = val;
  v->val = val;
  info->pending = v;
  info->pending = v;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Emit pending variable definitions.  This is called after we see the
/* Emit pending variable definitions.  This is called after we see the
   N_LBRAC that starts the block.  */
   N_LBRAC that starts the block.  */
 
 
static bfd_boolean
static bfd_boolean
stab_emit_pending_vars (void *dhandle, struct stab_handle *info)
stab_emit_pending_vars (void *dhandle, struct stab_handle *info)
{
{
  struct stab_pending_var *v;
  struct stab_pending_var *v;
 
 
  v = info->pending;
  v = info->pending;
  while (v != NULL)
  while (v != NULL)
    {
    {
      struct stab_pending_var *next;
      struct stab_pending_var *next;
 
 
      if (! debug_record_variable (dhandle, v->name, v->type, v->kind, v->val))
      if (! debug_record_variable (dhandle, v->name, v->type, v->kind, v->val))
        return FALSE;
        return FALSE;
 
 
      next = v->next;
      next = v->next;
      free (v);
      free (v);
      v = next;
      v = next;
    }
    }
 
 
  info->pending = NULL;
  info->pending = NULL;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Find the slot for a type in the database.  */
/* Find the slot for a type in the database.  */
 
 
static debug_type *
static debug_type *
stab_find_slot (struct stab_handle *info, const int *typenums)
stab_find_slot (struct stab_handle *info, const int *typenums)
{
{
  int filenum;
  int filenum;
  int index;
  int index;
  struct stab_types **ps;
  struct stab_types **ps;
 
 
  filenum = typenums[0];
  filenum = typenums[0];
  index = typenums[1];
  index = typenums[1];
 
 
  if (filenum < 0 || (unsigned int) filenum >= info->files)
  if (filenum < 0 || (unsigned int) filenum >= info->files)
    {
    {
      fprintf (stderr, _("Type file number %d out of range\n"), filenum);
      fprintf (stderr, _("Type file number %d out of range\n"), filenum);
      return NULL;
      return NULL;
    }
    }
  if (index < 0)
  if (index < 0)
    {
    {
      fprintf (stderr, _("Type index number %d out of range\n"), index);
      fprintf (stderr, _("Type index number %d out of range\n"), index);
      return NULL;
      return NULL;
    }
    }
 
 
  ps = info->file_types + filenum;
  ps = info->file_types + filenum;
 
 
  while (index >= STAB_TYPES_SLOTS)
  while (index >= STAB_TYPES_SLOTS)
    {
    {
      if (*ps == NULL)
      if (*ps == NULL)
        {
        {
          *ps = (struct stab_types *) xmalloc (sizeof **ps);
          *ps = (struct stab_types *) xmalloc (sizeof **ps);
          memset (*ps, 0, sizeof **ps);
          memset (*ps, 0, sizeof **ps);
        }
        }
      ps = &(*ps)->next;
      ps = &(*ps)->next;
      index -= STAB_TYPES_SLOTS;
      index -= STAB_TYPES_SLOTS;
    }
    }
  if (*ps == NULL)
  if (*ps == NULL)
    {
    {
      *ps = (struct stab_types *) xmalloc (sizeof **ps);
      *ps = (struct stab_types *) xmalloc (sizeof **ps);
      memset (*ps, 0, sizeof **ps);
      memset (*ps, 0, sizeof **ps);
    }
    }
 
 
  return (*ps)->types + index;
  return (*ps)->types + index;
}
}
 
 
/* Find a type given a type number.  If the type has not been
/* Find a type given a type number.  If the type has not been
   allocated yet, create an indirect type.  */
   allocated yet, create an indirect type.  */
 
 
static debug_type
static debug_type
stab_find_type (void *dhandle, struct stab_handle *info, const int *typenums)
stab_find_type (void *dhandle, struct stab_handle *info, const int *typenums)
{
{
  debug_type *slot;
  debug_type *slot;
 
 
  if (typenums[0] == 0 && typenums[1] < 0)
  if (typenums[0] == 0 && typenums[1] < 0)
    {
    {
      /* A negative type number indicates an XCOFF builtin type.  */
      /* A negative type number indicates an XCOFF builtin type.  */
      return stab_xcoff_builtin_type (dhandle, info, typenums[1]);
      return stab_xcoff_builtin_type (dhandle, info, typenums[1]);
    }
    }
 
 
  slot = stab_find_slot (info, typenums);
  slot = stab_find_slot (info, typenums);
  if (slot == NULL)
  if (slot == NULL)
    return DEBUG_TYPE_NULL;
    return DEBUG_TYPE_NULL;
 
 
  if (*slot == DEBUG_TYPE_NULL)
  if (*slot == DEBUG_TYPE_NULL)
    return debug_make_indirect_type (dhandle, slot, (const char *) NULL);
    return debug_make_indirect_type (dhandle, slot, (const char *) NULL);
 
 
  return *slot;
  return *slot;
}
}
 
 
/* Record that a given type number refers to a given type.  */
/* Record that a given type number refers to a given type.  */
 
 
static bfd_boolean
static bfd_boolean
stab_record_type (void *dhandle ATTRIBUTE_UNUSED, struct stab_handle *info,
stab_record_type (void *dhandle ATTRIBUTE_UNUSED, struct stab_handle *info,
                  const int *typenums, debug_type type)
                  const int *typenums, debug_type type)
{
{
  debug_type *slot;
  debug_type *slot;
 
 
  slot = stab_find_slot (info, typenums);
  slot = stab_find_slot (info, typenums);
  if (slot == NULL)
  if (slot == NULL)
    return FALSE;
    return FALSE;
 
 
  /* gdb appears to ignore type redefinitions, so we do as well.  */
  /* gdb appears to ignore type redefinitions, so we do as well.  */
 
 
  *slot = type;
  *slot = type;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Return an XCOFF builtin type.  */
/* Return an XCOFF builtin type.  */
 
 
static debug_type
static debug_type
stab_xcoff_builtin_type (void *dhandle, struct stab_handle *info,
stab_xcoff_builtin_type (void *dhandle, struct stab_handle *info,
                         int typenum)
                         int typenum)
{
{
  debug_type rettype;
  debug_type rettype;
  const char *name;
  const char *name;
 
 
  if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT)
  if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT)
    {
    {
      fprintf (stderr, _("Unrecognized XCOFF type %d\n"), typenum);
      fprintf (stderr, _("Unrecognized XCOFF type %d\n"), typenum);
      return DEBUG_TYPE_NULL;
      return DEBUG_TYPE_NULL;
    }
    }
  if (info->xcoff_types[-typenum] != NULL)
  if (info->xcoff_types[-typenum] != NULL)
    return info->xcoff_types[-typenum];
    return info->xcoff_types[-typenum];
 
 
  switch (-typenum)
  switch (-typenum)
    {
    {
    case 1:
    case 1:
      /* The size of this and all the other types are fixed, defined
      /* The size of this and all the other types are fixed, defined
         by the debugging format.  */
         by the debugging format.  */
      name = "int";
      name = "int";
      rettype = debug_make_int_type (dhandle, 4, FALSE);
      rettype = debug_make_int_type (dhandle, 4, FALSE);
      break;
      break;
    case 2:
    case 2:
      name = "char";
      name = "char";
      rettype = debug_make_int_type (dhandle, 1, FALSE);
      rettype = debug_make_int_type (dhandle, 1, FALSE);
      break;
      break;
    case 3:
    case 3:
      name = "short";
      name = "short";
      rettype = debug_make_int_type (dhandle, 2, FALSE);
      rettype = debug_make_int_type (dhandle, 2, FALSE);
      break;
      break;
    case 4:
    case 4:
      name = "long";
      name = "long";
      rettype = debug_make_int_type (dhandle, 4, FALSE);
      rettype = debug_make_int_type (dhandle, 4, FALSE);
      break;
      break;
    case 5:
    case 5:
      name = "unsigned char";
      name = "unsigned char";
      rettype = debug_make_int_type (dhandle, 1, TRUE);
      rettype = debug_make_int_type (dhandle, 1, TRUE);
      break;
      break;
    case 6:
    case 6:
      name = "signed char";
      name = "signed char";
      rettype = debug_make_int_type (dhandle, 1, FALSE);
      rettype = debug_make_int_type (dhandle, 1, FALSE);
      break;
      break;
    case 7:
    case 7:
      name = "unsigned short";
      name = "unsigned short";
      rettype = debug_make_int_type (dhandle, 2, TRUE);
      rettype = debug_make_int_type (dhandle, 2, TRUE);
      break;
      break;
    case 8:
    case 8:
      name = "unsigned int";
      name = "unsigned int";
      rettype = debug_make_int_type (dhandle, 4, TRUE);
      rettype = debug_make_int_type (dhandle, 4, TRUE);
      break;
      break;
    case 9:
    case 9:
      name = "unsigned";
      name = "unsigned";
      rettype = debug_make_int_type (dhandle, 4, TRUE);
      rettype = debug_make_int_type (dhandle, 4, TRUE);
    case 10:
    case 10:
      name = "unsigned long";
      name = "unsigned long";
      rettype = debug_make_int_type (dhandle, 4, TRUE);
      rettype = debug_make_int_type (dhandle, 4, TRUE);
      break;
      break;
    case 11:
    case 11:
      name = "void";
      name = "void";
      rettype = debug_make_void_type (dhandle);
      rettype = debug_make_void_type (dhandle);
      break;
      break;
    case 12:
    case 12:
      /* IEEE single precision (32 bit).  */
      /* IEEE single precision (32 bit).  */
      name = "float";
      name = "float";
      rettype = debug_make_float_type (dhandle, 4);
      rettype = debug_make_float_type (dhandle, 4);
      break;
      break;
    case 13:
    case 13:
      /* IEEE double precision (64 bit).  */
      /* IEEE double precision (64 bit).  */
      name = "double";
      name = "double";
      rettype = debug_make_float_type (dhandle, 8);
      rettype = debug_make_float_type (dhandle, 8);
      break;
      break;
    case 14:
    case 14:
      /* This is an IEEE double on the RS/6000, and different machines
      /* This is an IEEE double on the RS/6000, and different machines
         with different sizes for "long double" should use different
         with different sizes for "long double" should use different
         negative type numbers.  See stabs.texinfo.  */
         negative type numbers.  See stabs.texinfo.  */
      name = "long double";
      name = "long double";
      rettype = debug_make_float_type (dhandle, 8);
      rettype = debug_make_float_type (dhandle, 8);
      break;
      break;
    case 15:
    case 15:
      name = "integer";
      name = "integer";
      rettype = debug_make_int_type (dhandle, 4, FALSE);
      rettype = debug_make_int_type (dhandle, 4, FALSE);
      break;
      break;
    case 16:
    case 16:
      name = "boolean";
      name = "boolean";
      rettype = debug_make_bool_type (dhandle, 4);
      rettype = debug_make_bool_type (dhandle, 4);
      break;
      break;
    case 17:
    case 17:
      name = "short real";
      name = "short real";
      rettype = debug_make_float_type (dhandle, 4);
      rettype = debug_make_float_type (dhandle, 4);
      break;
      break;
    case 18:
    case 18:
      name = "real";
      name = "real";
      rettype = debug_make_float_type (dhandle, 8);
      rettype = debug_make_float_type (dhandle, 8);
      break;
      break;
    case 19:
    case 19:
      /* FIXME */
      /* FIXME */
      name = "stringptr";
      name = "stringptr";
      rettype = NULL;
      rettype = NULL;
      break;
      break;
    case 20:
    case 20:
      /* FIXME */
      /* FIXME */
      name = "character";
      name = "character";
      rettype = debug_make_int_type (dhandle, 1, TRUE);
      rettype = debug_make_int_type (dhandle, 1, TRUE);
      break;
      break;
    case 21:
    case 21:
      name = "logical*1";
      name = "logical*1";
      rettype = debug_make_bool_type (dhandle, 1);
      rettype = debug_make_bool_type (dhandle, 1);
      break;
      break;
    case 22:
    case 22:
      name = "logical*2";
      name = "logical*2";
      rettype = debug_make_bool_type (dhandle, 2);
      rettype = debug_make_bool_type (dhandle, 2);
      break;
      break;
    case 23:
    case 23:
      name = "logical*4";
      name = "logical*4";
      rettype = debug_make_bool_type (dhandle, 4);
      rettype = debug_make_bool_type (dhandle, 4);
      break;
      break;
    case 24:
    case 24:
      name = "logical";
      name = "logical";
      rettype = debug_make_bool_type (dhandle, 4);
      rettype = debug_make_bool_type (dhandle, 4);
      break;
      break;
    case 25:
    case 25:
      /* Complex type consisting of two IEEE single precision values.  */
      /* Complex type consisting of two IEEE single precision values.  */
      name = "complex";
      name = "complex";
      rettype = debug_make_complex_type (dhandle, 8);
      rettype = debug_make_complex_type (dhandle, 8);
      break;
      break;
    case 26:
    case 26:
      /* Complex type consisting of two IEEE double precision values.  */
      /* Complex type consisting of two IEEE double precision values.  */
      name = "double complex";
      name = "double complex";
      rettype = debug_make_complex_type (dhandle, 16);
      rettype = debug_make_complex_type (dhandle, 16);
      break;
      break;
    case 27:
    case 27:
      name = "integer*1";
      name = "integer*1";
      rettype = debug_make_int_type (dhandle, 1, FALSE);
      rettype = debug_make_int_type (dhandle, 1, FALSE);
      break;
      break;
    case 28:
    case 28:
      name = "integer*2";
      name = "integer*2";
      rettype = debug_make_int_type (dhandle, 2, FALSE);
      rettype = debug_make_int_type (dhandle, 2, FALSE);
      break;
      break;
    case 29:
    case 29:
      name = "integer*4";
      name = "integer*4";
      rettype = debug_make_int_type (dhandle, 4, FALSE);
      rettype = debug_make_int_type (dhandle, 4, FALSE);
      break;
      break;
    case 30:
    case 30:
      /* FIXME */
      /* FIXME */
      name = "wchar";
      name = "wchar";
      rettype = debug_make_int_type (dhandle, 2, FALSE);
      rettype = debug_make_int_type (dhandle, 2, FALSE);
      break;
      break;
    case 31:
    case 31:
      name = "long long";
      name = "long long";
      rettype = debug_make_int_type (dhandle, 8, FALSE);
      rettype = debug_make_int_type (dhandle, 8, FALSE);
      break;
      break;
    case 32:
    case 32:
      name = "unsigned long long";
      name = "unsigned long long";
      rettype = debug_make_int_type (dhandle, 8, TRUE);
      rettype = debug_make_int_type (dhandle, 8, TRUE);
      break;
      break;
    case 33:
    case 33:
      name = "logical*8";
      name = "logical*8";
      rettype = debug_make_bool_type (dhandle, 8);
      rettype = debug_make_bool_type (dhandle, 8);
      break;
      break;
    case 34:
    case 34:
      name = "integer*8";
      name = "integer*8";
      rettype = debug_make_int_type (dhandle, 8, FALSE);
      rettype = debug_make_int_type (dhandle, 8, FALSE);
      break;
      break;
    default:
    default:
      abort ();
      abort ();
    }
    }
 
 
  rettype = debug_name_type (dhandle, name, rettype);
  rettype = debug_name_type (dhandle, name, rettype);
 
 
  info->xcoff_types[-typenum] = rettype;
  info->xcoff_types[-typenum] = rettype;
 
 
  return rettype;
  return rettype;
}
}
 
 
/* Find or create a tagged type.  */
/* Find or create a tagged type.  */
 
 
static debug_type
static debug_type
stab_find_tagged_type (void *dhandle, struct stab_handle *info,
stab_find_tagged_type (void *dhandle, struct stab_handle *info,
                       const char *p, int len, enum debug_type_kind kind)
                       const char *p, int len, enum debug_type_kind kind)
{
{
  char *name;
  char *name;
  debug_type dtype;
  debug_type dtype;
  struct stab_tag *st;
  struct stab_tag *st;
 
 
  name = savestring (p, len);
  name = savestring (p, len);
 
 
  /* We pass DEBUG_KIND_ILLEGAL because we want all tags in the same
  /* 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
     namespace.  This is right for C, and I don't know how to handle
     other languages.  FIXME.  */
     other languages.  FIXME.  */
  dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL);
  dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL);
  if (dtype != DEBUG_TYPE_NULL)
  if (dtype != DEBUG_TYPE_NULL)
    {
    {
      free (name);
      free (name);
      return dtype;
      return dtype;
    }
    }
 
 
  /* We need to allocate an entry on the undefined tag list.  */
  /* We need to allocate an entry on the undefined tag list.  */
  for (st = info->tags; st != NULL; st = st->next)
  for (st = info->tags; st != NULL; st = st->next)
    {
    {
      if (st->name[0] == name[0]
      if (st->name[0] == name[0]
          && strcmp (st->name, name) == 0)
          && strcmp (st->name, name) == 0)
        {
        {
          if (st->kind == DEBUG_KIND_ILLEGAL)
          if (st->kind == DEBUG_KIND_ILLEGAL)
            st->kind = kind;
            st->kind = kind;
          free (name);
          free (name);
          break;
          break;
        }
        }
    }
    }
  if (st == NULL)
  if (st == NULL)
    {
    {
      st = (struct stab_tag *) xmalloc (sizeof *st);
      st = (struct stab_tag *) xmalloc (sizeof *st);
      memset (st, 0, sizeof *st);
      memset (st, 0, sizeof *st);
 
 
      st->next = info->tags;
      st->next = info->tags;
      st->name = name;
      st->name = name;
      st->kind = kind;
      st->kind = kind;
      st->slot = DEBUG_TYPE_NULL;
      st->slot = DEBUG_TYPE_NULL;
      st->type = debug_make_indirect_type (dhandle, &st->slot, name);
      st->type = debug_make_indirect_type (dhandle, &st->slot, name);
      info->tags = st;
      info->tags = st;
    }
    }
 
 
  return st->type;
  return st->type;
}
}


/* In order to get the correct argument types for a stubbed method, we
/* In order to get the correct argument types for a stubbed method, we
   need to extract the argument types from a C++ mangled string.
   need to extract the argument types from a C++ mangled string.
   Since the argument types can refer back to the return type, this
   Since the argument types can refer back to the return type, this
   means that we must demangle the entire physical name.  In gdb this
   means that we must demangle the entire physical name.  In gdb this
   is done by calling cplus_demangle and running the results back
   is done by calling cplus_demangle and running the results back
   through the C++ expression parser.  Since we have no expression
   through the C++ expression parser.  Since we have no expression
   parser, we must duplicate much of the work of cplus_demangle here.
   parser, we must duplicate much of the work of cplus_demangle here.
 
 
   We assume that GNU style demangling is used, since this is only
   We assume that GNU style demangling is used, since this is only
   done for method stubs, and only g++ should output that form of
   done for method stubs, and only g++ should output that form of
   debugging information.  */
   debugging information.  */
 
 
/* This structure is used to hold a pointer to type information which
/* This structure is used to hold a pointer to type information which
   demangling a string.  */
   demangling a string.  */
 
 
struct stab_demangle_typestring
struct stab_demangle_typestring
{
{
  /* The start of the type.  This is not null terminated.  */
  /* The start of the type.  This is not null terminated.  */
  const char *typestring;
  const char *typestring;
  /* The length of the type.  */
  /* The length of the type.  */
  unsigned int len;
  unsigned int len;
};
};
 
 
/* This structure is used to hold information while demangling a
/* This structure is used to hold information while demangling a
   string.  */
   string.  */
 
 
struct stab_demangle_info
struct stab_demangle_info
{
{
  /* The debugging information handle.  */
  /* The debugging information handle.  */
  void *dhandle;
  void *dhandle;
  /* The stab information handle.  */
  /* The stab information handle.  */
  struct stab_handle *info;
  struct stab_handle *info;
  /* The array of arguments we are building.  */
  /* The array of arguments we are building.  */
  debug_type *args;
  debug_type *args;
  /* Whether the method takes a variable number of arguments.  */
  /* Whether the method takes a variable number of arguments.  */
  bfd_boolean varargs;
  bfd_boolean varargs;
  /* The array of types we have remembered.  */
  /* The array of types we have remembered.  */
  struct stab_demangle_typestring *typestrings;
  struct stab_demangle_typestring *typestrings;
  /* The number of typestrings.  */
  /* The number of typestrings.  */
  unsigned int typestring_count;
  unsigned int typestring_count;
  /* The number of typestring slots we have allocated.  */
  /* The number of typestring slots we have allocated.  */
  unsigned int typestring_alloc;
  unsigned int typestring_alloc;
};
};
 
 
static void stab_bad_demangle (const char *);
static void stab_bad_demangle (const char *);
static unsigned int stab_demangle_count (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_get_count (const char **, unsigned int *);
static bfd_boolean stab_demangle_prefix
static bfd_boolean stab_demangle_prefix
  (struct stab_demangle_info *, const char **, unsigned int);
  (struct stab_demangle_info *, const char **, unsigned int);
static bfd_boolean stab_demangle_function_name
static bfd_boolean stab_demangle_function_name
  (struct stab_demangle_info *, const char **, const char *);
  (struct stab_demangle_info *, const char **, const char *);
static bfd_boolean stab_demangle_signature
static bfd_boolean stab_demangle_signature
  (struct stab_demangle_info *, const char **);
  (struct stab_demangle_info *, const char **);
static bfd_boolean stab_demangle_qualified
static bfd_boolean stab_demangle_qualified
  (struct stab_demangle_info *, const char **, debug_type *);
  (struct stab_demangle_info *, const char **, debug_type *);
static bfd_boolean stab_demangle_template
static bfd_boolean stab_demangle_template
  (struct stab_demangle_info *, const char **, char **);
  (struct stab_demangle_info *, const char **, char **);
static bfd_boolean stab_demangle_class
static bfd_boolean stab_demangle_class
  (struct stab_demangle_info *, const char **, const char **);
  (struct stab_demangle_info *, const char **, const char **);
static bfd_boolean stab_demangle_args
static bfd_boolean stab_demangle_args
  (struct stab_demangle_info *, const char **, debug_type **, bfd_boolean *);
  (struct stab_demangle_info *, const char **, debug_type **, bfd_boolean *);
static bfd_boolean stab_demangle_arg
static bfd_boolean stab_demangle_arg
  (struct stab_demangle_info *, const char **, debug_type **,
  (struct stab_demangle_info *, const char **, debug_type **,
   unsigned int *, unsigned int *);
   unsigned int *, unsigned int *);
static bfd_boolean stab_demangle_type
static bfd_boolean stab_demangle_type
  (struct stab_demangle_info *, const char **, debug_type *);
  (struct stab_demangle_info *, const char **, debug_type *);
static bfd_boolean stab_demangle_fund_type
static bfd_boolean stab_demangle_fund_type
  (struct stab_demangle_info *, const char **, debug_type *);
  (struct stab_demangle_info *, const char **, debug_type *);
static bfd_boolean stab_demangle_remember_type
static bfd_boolean stab_demangle_remember_type
  (struct stab_demangle_info *, const char *, int);
  (struct stab_demangle_info *, const char *, int);
 
 
/* Warn about a bad demangling.  */
/* Warn about a bad demangling.  */
 
 
static void
static void
stab_bad_demangle (const char *s)
stab_bad_demangle (const char *s)
{
{
  fprintf (stderr, _("bad mangled name `%s'\n"), s);
  fprintf (stderr, _("bad mangled name `%s'\n"), s);
}
}
 
 
/* Get a count from a stab string.  */
/* Get a count from a stab string.  */
 
 
static unsigned int
static unsigned int
stab_demangle_count (const char **pp)
stab_demangle_count (const char **pp)
{
{
  unsigned int count;
  unsigned int count;
 
 
  count = 0;
  count = 0;
  while (ISDIGIT (**pp))
  while (ISDIGIT (**pp))
    {
    {
      count *= 10;
      count *= 10;
      count += **pp - '0';
      count += **pp - '0';
      ++*pp;
      ++*pp;
    }
    }
  return count;
  return count;
}
}
 
 
/* Require a count in a string.  The count may be multiple digits, in
/* Require a count in a string.  The count may be multiple digits, in
   which case it must end in an underscore.  */
   which case it must end in an underscore.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_get_count (const char **pp, unsigned int *pi)
stab_demangle_get_count (const char **pp, unsigned int *pi)
{
{
  if (! ISDIGIT (**pp))
  if (! ISDIGIT (**pp))
    return FALSE;
    return FALSE;
 
 
  *pi = **pp - '0';
  *pi = **pp - '0';
  ++*pp;
  ++*pp;
  if (ISDIGIT (**pp))
  if (ISDIGIT (**pp))
    {
    {
      unsigned int count;
      unsigned int count;
      const char *p;
      const char *p;
 
 
      count = *pi;
      count = *pi;
      p = *pp;
      p = *pp;
      do
      do
        {
        {
          count *= 10;
          count *= 10;
          count += *p - '0';
          count += *p - '0';
          ++p;
          ++p;
        }
        }
      while (ISDIGIT (*p));
      while (ISDIGIT (*p));
      if (*p == '_')
      if (*p == '_')
        {
        {
          *pp = p + 1;
          *pp = p + 1;
          *pi = count;
          *pi = count;
        }
        }
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* This function demangles a physical name, returning a NULL
/* This function demangles a physical name, returning a NULL
   terminated array of argument types.  */
   terminated array of argument types.  */
 
 
static debug_type *
static debug_type *
stab_demangle_argtypes (void *dhandle, struct stab_handle *info,
stab_demangle_argtypes (void *dhandle, struct stab_handle *info,
                        const char *physname, bfd_boolean *pvarargs,
                        const char *physname, bfd_boolean *pvarargs,
                        unsigned int physname_len)
                        unsigned int physname_len)
{
{
  struct stab_demangle_info minfo;
  struct stab_demangle_info minfo;
 
 
  /* Check for the g++ V3 ABI.  */
  /* Check for the g++ V3 ABI.  */
  if (physname[0] == '_' && physname[1] == 'Z')
  if (physname[0] == '_' && physname[1] == 'Z')
    return stab_demangle_v3_argtypes (dhandle, info, physname, pvarargs);
    return stab_demangle_v3_argtypes (dhandle, info, physname, pvarargs);
 
 
  minfo.dhandle = dhandle;
  minfo.dhandle = dhandle;
  minfo.info = info;
  minfo.info = info;
  minfo.args = NULL;
  minfo.args = NULL;
  minfo.varargs = FALSE;
  minfo.varargs = FALSE;
  minfo.typestring_alloc = 10;
  minfo.typestring_alloc = 10;
  minfo.typestrings = ((struct stab_demangle_typestring *)
  minfo.typestrings = ((struct stab_demangle_typestring *)
                       xmalloc (minfo.typestring_alloc
                       xmalloc (minfo.typestring_alloc
                                * sizeof *minfo.typestrings));
                                * sizeof *minfo.typestrings));
  minfo.typestring_count = 0;
  minfo.typestring_count = 0;
 
 
  /* cplus_demangle checks for special GNU mangled forms, but we can't
  /* cplus_demangle checks for special GNU mangled forms, but we can't
     see any of them in mangled method argument types.  */
     see any of them in mangled method argument types.  */
 
 
  if (! stab_demangle_prefix (&minfo, &physname, physname_len))
  if (! stab_demangle_prefix (&minfo, &physname, physname_len))
    goto error_return;
    goto error_return;
 
 
  if (*physname != '\0')
  if (*physname != '\0')
    {
    {
      if (! stab_demangle_signature (&minfo, &physname))
      if (! stab_demangle_signature (&minfo, &physname))
        goto error_return;
        goto error_return;
    }
    }
 
 
  free (minfo.typestrings);
  free (minfo.typestrings);
  minfo.typestrings = NULL;
  minfo.typestrings = NULL;
 
 
  if (minfo.args == NULL)
  if (minfo.args == NULL)
    fprintf (stderr, _("no argument types in mangled string\n"));
    fprintf (stderr, _("no argument types in mangled string\n"));
 
 
  *pvarargs = minfo.varargs;
  *pvarargs = minfo.varargs;
  return minfo.args;
  return minfo.args;
 
 
 error_return:
 error_return:
  if (minfo.typestrings != NULL)
  if (minfo.typestrings != NULL)
    free (minfo.typestrings);
    free (minfo.typestrings);
  return NULL;
  return NULL;
}
}
 
 
/* Demangle the prefix of the mangled name.  */
/* Demangle the prefix of the mangled name.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_prefix (struct stab_demangle_info *minfo, const char **pp,
stab_demangle_prefix (struct stab_demangle_info *minfo, const char **pp,
                      unsigned int physname_len)
                      unsigned int physname_len)
{
{
  const char *scan;
  const char *scan;
  unsigned int i;
  unsigned int i;
 
 
  /* cplus_demangle checks for global constructors and destructors,
  /* cplus_demangle checks for global constructors and destructors,
     but we can't see them in mangled argument types.  */
     but we can't see them in mangled argument types.  */
 
 
  if (physname_len)
  if (physname_len)
    scan = *pp + physname_len;
    scan = *pp + physname_len;
  else
  else
    {
    {
      /* Look for `__'.  */
      /* Look for `__'.  */
      scan = *pp;
      scan = *pp;
      do
      do
        scan = strchr (scan, '_');
        scan = strchr (scan, '_');
      while (scan != NULL && *++scan != '_');
      while (scan != NULL && *++scan != '_');
 
 
      if (scan == NULL)
      if (scan == NULL)
        {
        {
          stab_bad_demangle (*pp);
          stab_bad_demangle (*pp);
          return FALSE;
          return FALSE;
        }
        }
 
 
      --scan;
      --scan;
 
 
      /* We found `__'; move ahead to the last contiguous `__' pair.  */
      /* We found `__'; move ahead to the last contiguous `__' pair.  */
      i = strspn (scan, "_");
      i = strspn (scan, "_");
      if (i > 2)
      if (i > 2)
        scan += i - 2;
        scan += i - 2;
    }
    }
 
 
  if (scan == *pp
  if (scan == *pp
      && (ISDIGIT (scan[2])
      && (ISDIGIT (scan[2])
          || scan[2] == 'Q'
          || scan[2] == 'Q'
          || scan[2] == 't'))
          || scan[2] == 't'))
    {
    {
      /* This is a GNU style constructor name.  */
      /* This is a GNU style constructor name.  */
      *pp = scan + 2;
      *pp = scan + 2;
      return TRUE;
      return TRUE;
    }
    }
  else if (scan == *pp
  else if (scan == *pp
           && ! ISDIGIT (scan[2])
           && ! ISDIGIT (scan[2])
           && scan[2] != 't')
           && scan[2] != 't')
    {
    {
      /* Look for the `__' that separates the prefix from the
      /* Look for the `__' that separates the prefix from the
         signature.  */
         signature.  */
      while (*scan == '_')
      while (*scan == '_')
        ++scan;
        ++scan;
      scan = strstr (scan, "__");
      scan = strstr (scan, "__");
      if (scan == NULL || scan[2] == '\0')
      if (scan == NULL || scan[2] == '\0')
        {
        {
          stab_bad_demangle (*pp);
          stab_bad_demangle (*pp);
          return FALSE;
          return FALSE;
        }
        }
 
 
      return stab_demangle_function_name (minfo, pp, scan);
      return stab_demangle_function_name (minfo, pp, scan);
    }
    }
  else if (scan[2] != '\0')
  else if (scan[2] != '\0')
    {
    {
      /* The name doesn't start with `__', but it does contain `__'.  */
      /* The name doesn't start with `__', but it does contain `__'.  */
      return stab_demangle_function_name (minfo, pp, scan);
      return stab_demangle_function_name (minfo, pp, scan);
    }
    }
  else
  else
    {
    {
      stab_bad_demangle (*pp);
      stab_bad_demangle (*pp);
      return FALSE;
      return FALSE;
    }
    }
  /*NOTREACHED*/
  /*NOTREACHED*/
}
}
 
 
/* Demangle a function name prefix.  The scan argument points to the
/* Demangle a function name prefix.  The scan argument points to the
   double underscore which separates the function name from the
   double underscore which separates the function name from the
   signature.  */
   signature.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_function_name (struct stab_demangle_info *minfo,
stab_demangle_function_name (struct stab_demangle_info *minfo,
                             const char **pp, const char *scan)
                             const char **pp, const char *scan)
{
{
  const char *name;
  const char *name;
 
 
  /* The string from *pp to scan is the name of the function.  We
  /* 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
     don't care about the name, since we just looking for argument
     types.  However, for conversion operators, the name may include a
     types.  However, for conversion operators, the name may include a
     type which we must remember in order to handle backreferences.  */
     type which we must remember in order to handle backreferences.  */
 
 
  name = *pp;
  name = *pp;
  *pp = scan + 2;
  *pp = scan + 2;
 
 
  if (*pp - name >= 5
  if (*pp - name >= 5
           && CONST_STRNEQ (name, "type")
           && CONST_STRNEQ (name, "type")
           && (name[4] == '$' || name[4] == '.'))
           && (name[4] == '$' || name[4] == '.'))
    {
    {
      const char *tem;
      const char *tem;
 
 
      /* This is a type conversion operator.  */
      /* This is a type conversion operator.  */
      tem = name + 5;
      tem = name + 5;
      if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
      if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
        return FALSE;
        return FALSE;
    }
    }
  else if (name[0] == '_'
  else if (name[0] == '_'
           && name[1] == '_'
           && name[1] == '_'
           && name[2] == 'o'
           && name[2] == 'o'
           && name[3] == 'p')
           && name[3] == 'p')
    {
    {
      const char *tem;
      const char *tem;
 
 
      /* This is a type conversion operator.  */
      /* This is a type conversion operator.  */
      tem = name + 4;
      tem = name + 4;
      if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
      if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
        return FALSE;
        return FALSE;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Demangle the signature.  This is where the argument types are
/* Demangle the signature.  This is where the argument types are
   found.  */
   found.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_signature (struct stab_demangle_info *minfo, const char **pp)
stab_demangle_signature (struct stab_demangle_info *minfo, const char **pp)
{
{
  const char *orig;
  const char *orig;
  bfd_boolean expect_func, func_done;
  bfd_boolean expect_func, func_done;
  const char *hold;
  const char *hold;
 
 
  orig = *pp;
  orig = *pp;
 
 
  expect_func = FALSE;
  expect_func = FALSE;
  func_done = FALSE;
  func_done = FALSE;
  hold = NULL;
  hold = NULL;
 
 
  while (**pp != '\0')
  while (**pp != '\0')
    {
    {
      switch (**pp)
      switch (**pp)
        {
        {
        case 'Q':
        case 'Q':
          hold = *pp;
          hold = *pp;
          if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL)
          if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL)
              || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
              || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
            return FALSE;
            return FALSE;
          expect_func = TRUE;
          expect_func = TRUE;
          hold = NULL;
          hold = NULL;
          break;
          break;
 
 
        case 'S':
        case 'S':
          /* Static member function.  FIXME: Can this happen?  */
          /* Static member function.  FIXME: Can this happen?  */
          if (hold == NULL)
          if (hold == NULL)
            hold = *pp;
            hold = *pp;
          ++*pp;
          ++*pp;
          break;
          break;
 
 
        case 'C':
        case 'C':
          /* Const member function.  */
          /* Const member function.  */
          if (hold == NULL)
          if (hold == NULL)
            hold = *pp;
            hold = *pp;
          ++*pp;
          ++*pp;
          break;
          break;
 
 
        case '0': case '1': case '2': case '3': case '4':
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
        case '5': case '6': case '7': case '8': case '9':
          if (hold == NULL)
          if (hold == NULL)
            hold = *pp;
            hold = *pp;
          if (! stab_demangle_class (minfo, pp, (const char **) NULL)
          if (! stab_demangle_class (minfo, pp, (const char **) NULL)
              || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
              || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
            return FALSE;
            return FALSE;
          expect_func = TRUE;
          expect_func = TRUE;
          hold = NULL;
          hold = NULL;
          break;
          break;
 
 
        case 'F':
        case 'F':
          /* Function.  I don't know if this actually happens with g++
          /* Function.  I don't know if this actually happens with g++
             output.  */
             output.  */
          hold = NULL;
          hold = NULL;
          func_done = TRUE;
          func_done = TRUE;
          ++*pp;
          ++*pp;
          if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
          if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
            return FALSE;
            return FALSE;
          break;
          break;
 
 
        case 't':
        case 't':
          /* Template.  */
          /* Template.  */
          if (hold == NULL)
          if (hold == NULL)
            hold = *pp;
            hold = *pp;
          if (! stab_demangle_template (minfo, pp, (char **) NULL)
          if (! stab_demangle_template (minfo, pp, (char **) NULL)
              || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
              || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
            return FALSE;
            return FALSE;
          hold = NULL;
          hold = NULL;
          expect_func = TRUE;
          expect_func = TRUE;
          break;
          break;
 
 
        case '_':
        case '_':
          /* At the outermost level, we cannot have a return type
          /* At the outermost level, we cannot have a return type
             specified, so if we run into another '_' at this point we
             specified, so if we run into another '_' at this point we
             are dealing with a mangled name that is either bogus, or
             are dealing with a mangled name that is either bogus, or
             has been mangled by some algorithm we don't know how to
             has been mangled by some algorithm we don't know how to
             deal with.  So just reject the entire demangling.  */
             deal with.  So just reject the entire demangling.  */
          stab_bad_demangle (orig);
          stab_bad_demangle (orig);
          return FALSE;
          return FALSE;
 
 
        default:
        default:
          /* Assume we have stumbled onto the first outermost function
          /* Assume we have stumbled onto the first outermost function
             argument token, and start processing args.  */
             argument token, and start processing args.  */
          func_done = TRUE;
          func_done = TRUE;
          if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
          if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
            return FALSE;
            return FALSE;
          break;
          break;
        }
        }
 
 
      if (expect_func)
      if (expect_func)
        {
        {
          func_done = TRUE;
          func_done = TRUE;
          if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
          if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
            return FALSE;
            return FALSE;
        }
        }
    }
    }
 
 
  if (! func_done)
  if (! func_done)
    {
    {
      /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
      /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
         bar__3fooi is 'foo::bar(int)'.  We get here when we find the
         bar__3fooi is 'foo::bar(int)'.  We get here when we find the
         first case, and need to ensure that the '(void)' gets added
         first case, and need to ensure that the '(void)' gets added
         to the current declp.  */
         to the current declp.  */
      if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
      if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
        return FALSE;
        return FALSE;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Demangle a qualified name, such as "Q25Outer5Inner" which is the
/* Demangle a qualified name, such as "Q25Outer5Inner" which is the
   mangled form of "Outer::Inner".  */
   mangled form of "Outer::Inner".  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_qualified (struct stab_demangle_info *minfo, const char **pp,
stab_demangle_qualified (struct stab_demangle_info *minfo, const char **pp,
                         debug_type *ptype)
                         debug_type *ptype)
{
{
  const char *orig;
  const char *orig;
  const char *p;
  const char *p;
  unsigned int qualifiers;
  unsigned int qualifiers;
  debug_type context;
  debug_type context;
 
 
  orig = *pp;
  orig = *pp;
 
 
  switch ((*pp)[1])
  switch ((*pp)[1])
    {
    {
    case '_':
    case '_':
      /* GNU mangled name with more than 9 classes.  The count is
      /* GNU mangled name with more than 9 classes.  The count is
         preceded by an underscore (to distinguish it from the <= 9
         preceded by an underscore (to distinguish it from the <= 9
         case) and followed by an underscore.  */
         case) and followed by an underscore.  */
      p = *pp + 2;
      p = *pp + 2;
      if (! ISDIGIT (*p) || *p == '0')
      if (! ISDIGIT (*p) || *p == '0')
        {
        {
          stab_bad_demangle (orig);
          stab_bad_demangle (orig);
          return FALSE;
          return FALSE;
        }
        }
      qualifiers = atoi (p);
      qualifiers = atoi (p);
      while (ISDIGIT (*p))
      while (ISDIGIT (*p))
        ++p;
        ++p;
      if (*p != '_')
      if (*p != '_')
        {
        {
          stab_bad_demangle (orig);
          stab_bad_demangle (orig);
          return FALSE;
          return FALSE;
        }
        }
      *pp = p + 1;
      *pp = p + 1;
      break;
      break;
 
 
    case '1': case '2': case '3': case '4': case '5':
    case '1': case '2': case '3': case '4': case '5':
    case '6': case '7': case '8': case '9':
    case '6': case '7': case '8': case '9':
      qualifiers = (*pp)[1] - '0';
      qualifiers = (*pp)[1] - '0';
      /* Skip an optional underscore after the count.  */
      /* Skip an optional underscore after the count.  */
      if ((*pp)[2] == '_')
      if ((*pp)[2] == '_')
        ++*pp;
        ++*pp;
      *pp += 2;
      *pp += 2;
      break;
      break;
 
 
    case '0':
    case '0':
    default:
    default:
      stab_bad_demangle (orig);
      stab_bad_demangle (orig);
      return FALSE;
      return FALSE;
    }
    }
 
 
  context = DEBUG_TYPE_NULL;
  context = DEBUG_TYPE_NULL;
 
 
  /* Pick off the names.  */
  /* Pick off the names.  */
  while (qualifiers-- > 0)
  while (qualifiers-- > 0)
    {
    {
      if (**pp == '_')
      if (**pp == '_')
        ++*pp;
        ++*pp;
      if (**pp == 't')
      if (**pp == 't')
        {
        {
          char *name;
          char *name;
 
 
          if (! stab_demangle_template (minfo, pp,
          if (! stab_demangle_template (minfo, pp,
                                        ptype != NULL ? &name : NULL))
                                        ptype != NULL ? &name : NULL))
            return FALSE;
            return FALSE;
 
 
          if (ptype != NULL)
          if (ptype != NULL)
            {
            {
              context = stab_find_tagged_type (minfo->dhandle, minfo->info,
              context = stab_find_tagged_type (minfo->dhandle, minfo->info,
                                               name, strlen (name),
                                               name, strlen (name),
                                               DEBUG_KIND_CLASS);
                                               DEBUG_KIND_CLASS);
              free (name);
              free (name);
              if (context == DEBUG_TYPE_NULL)
              if (context == DEBUG_TYPE_NULL)
                return FALSE;
                return FALSE;
            }
            }
        }
        }
      else
      else
        {
        {
          unsigned int len;
          unsigned int len;
 
 
          len = stab_demangle_count (pp);
          len = stab_demangle_count (pp);
          if (strlen (*pp) < len)
          if (strlen (*pp) < len)
            {
            {
              stab_bad_demangle (orig);
              stab_bad_demangle (orig);
              return FALSE;
              return FALSE;
            }
            }
 
 
          if (ptype != NULL)
          if (ptype != NULL)
            {
            {
              const debug_field *fields;
              const debug_field *fields;
 
 
              fields = NULL;
              fields = NULL;
              if (context != DEBUG_TYPE_NULL)
              if (context != DEBUG_TYPE_NULL)
                fields = debug_get_fields (minfo->dhandle, context);
                fields = debug_get_fields (minfo->dhandle, context);
 
 
              context = DEBUG_TYPE_NULL;
              context = DEBUG_TYPE_NULL;
 
 
              if (fields != NULL)
              if (fields != NULL)
                {
                {
                  char *name;
                  char *name;
 
 
                  /* Try to find the type by looking through the
                  /* Try to find the type by looking through the
                     fields of context until we find a field with the
                     fields of context until we find a field with the
                     same type.  This ought to work for a class
                     same type.  This ought to work for a class
                     defined within a class, but it won't work for,
                     defined within a class, but it won't work for,
                     e.g., an enum defined within a class.  stabs does
                     e.g., an enum defined within a class.  stabs does
                     not give us enough information to figure out the
                     not give us enough information to figure out the
                     latter case.  */
                     latter case.  */
 
 
                  name = savestring (*pp, len);
                  name = savestring (*pp, len);
 
 
                  for (; *fields != DEBUG_FIELD_NULL; fields++)
                  for (; *fields != DEBUG_FIELD_NULL; fields++)
                    {
                    {
                      debug_type ft;
                      debug_type ft;
                      const char *dn;
                      const char *dn;
 
 
                      ft = debug_get_field_type (minfo->dhandle, *fields);
                      ft = debug_get_field_type (minfo->dhandle, *fields);
                      if (ft == NULL)
                      if (ft == NULL)
                        return FALSE;
                        return FALSE;
                      dn = debug_get_type_name (minfo->dhandle, ft);
                      dn = debug_get_type_name (minfo->dhandle, ft);
                      if (dn != NULL && strcmp (dn, name) == 0)
                      if (dn != NULL && strcmp (dn, name) == 0)
                        {
                        {
                          context = ft;
                          context = ft;
                          break;
                          break;
                        }
                        }
                    }
                    }
 
 
                  free (name);
                  free (name);
                }
                }
 
 
              if (context == DEBUG_TYPE_NULL)
              if (context == DEBUG_TYPE_NULL)
                {
                {
                  /* We have to fall back on finding the type by name.
                  /* We have to fall back on finding the type by name.
                     If there are more types to come, then this must
                     If there are more types to come, then this must
                     be a class.  Otherwise, it could be anything.  */
                     be a class.  Otherwise, it could be anything.  */
 
 
                  if (qualifiers == 0)
                  if (qualifiers == 0)
                    {
                    {
                      char *name;
                      char *name;
 
 
                      name = savestring (*pp, len);
                      name = savestring (*pp, len);
                      context = debug_find_named_type (minfo->dhandle,
                      context = debug_find_named_type (minfo->dhandle,
                                                       name);
                                                       name);
                      free (name);
                      free (name);
                    }
                    }
 
 
                  if (context == DEBUG_TYPE_NULL)
                  if (context == DEBUG_TYPE_NULL)
                    {
                    {
                      context = stab_find_tagged_type (minfo->dhandle,
                      context = stab_find_tagged_type (minfo->dhandle,
                                                       minfo->info,
                                                       minfo->info,
                                                       *pp, len,
                                                       *pp, len,
                                                       (qualifiers == 0
                                                       (qualifiers == 0
                                                        ? DEBUG_KIND_ILLEGAL
                                                        ? DEBUG_KIND_ILLEGAL
                                                        : DEBUG_KIND_CLASS));
                                                        : DEBUG_KIND_CLASS));
                      if (context == DEBUG_TYPE_NULL)
                      if (context == DEBUG_TYPE_NULL)
                        return FALSE;
                        return FALSE;
                    }
                    }
                }
                }
            }
            }
 
 
          *pp += len;
          *pp += len;
        }
        }
    }
    }
 
 
  if (ptype != NULL)
  if (ptype != NULL)
    *ptype = context;
    *ptype = context;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Demangle a template.  If PNAME is not NULL, this sets *PNAME to a
/* Demangle a template.  If PNAME is not NULL, this sets *PNAME to a
   string representation of the template.  */
   string representation of the template.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_template (struct stab_demangle_info *minfo, const char **pp,
stab_demangle_template (struct stab_demangle_info *minfo, const char **pp,
                        char **pname)
                        char **pname)
{
{
  const char *orig;
  const char *orig;
  unsigned int r, i;
  unsigned int r, i;
 
 
  orig = *pp;
  orig = *pp;
 
 
  ++*pp;
  ++*pp;
 
 
  /* Skip the template name.  */
  /* Skip the template name.  */
  r = stab_demangle_count (pp);
  r = stab_demangle_count (pp);
  if (r == 0 || strlen (*pp) < r)
  if (r == 0 || strlen (*pp) < r)
    {
    {
      stab_bad_demangle (orig);
      stab_bad_demangle (orig);
      return FALSE;
      return FALSE;
    }
    }
  *pp += r;
  *pp += r;
 
 
  /* Get the size of the parameter list.  */
  /* Get the size of the parameter list.  */
  if (stab_demangle_get_count (pp, &r) == 0)
  if (stab_demangle_get_count (pp, &r) == 0)
    {
    {
      stab_bad_demangle (orig);
      stab_bad_demangle (orig);
      return FALSE;
      return FALSE;
    }
    }
 
 
  for (i = 0; i < r; i++)
  for (i = 0; i < r; i++)
    {
    {
      if (**pp == 'Z')
      if (**pp == 'Z')
        {
        {
          /* This is a type parameter.  */
          /* This is a type parameter.  */
          ++*pp;
          ++*pp;
          if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
          if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
            return FALSE;
            return FALSE;
        }
        }
      else
      else
        {
        {
          const char *old_p;
          const char *old_p;
          bfd_boolean pointerp, realp, integralp, charp, boolp;
          bfd_boolean pointerp, realp, integralp, charp, boolp;
          bfd_boolean done;
          bfd_boolean done;
 
 
          old_p = *pp;
          old_p = *pp;
          pointerp = FALSE;
          pointerp = FALSE;
          realp = FALSE;
          realp = FALSE;
          integralp = FALSE;
          integralp = FALSE;
          charp = FALSE;
          charp = FALSE;
          boolp = FALSE;
          boolp = FALSE;
          done = FALSE;
          done = FALSE;
 
 
          /* This is a value parameter.  */
          /* This is a value parameter.  */
 
 
          if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
          if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
            return FALSE;
            return FALSE;
 
 
          while (*old_p != '\0' && ! done)
          while (*old_p != '\0' && ! done)
            {
            {
              switch (*old_p)
              switch (*old_p)
                {
                {
                case 'P':
                case 'P':
                case 'p':
                case 'p':
                case 'R':
                case 'R':
                  pointerp = TRUE;
                  pointerp = TRUE;
                  done = TRUE;
                  done = TRUE;
                  break;
                  break;
                case 'C':       /* Const.  */
                case 'C':       /* Const.  */
                case 'S':       /* Signed.  */
                case 'S':       /* Signed.  */
                case 'U':       /* Unsigned.  */
                case 'U':       /* Unsigned.  */
                case 'V':       /* Volatile.  */
                case 'V':       /* Volatile.  */
                case 'F':       /* Function.  */
                case 'F':       /* Function.  */
                case 'M':       /* Member function.  */
                case 'M':       /* Member function.  */
                case 'O':       /* ??? */
                case 'O':       /* ??? */
                  ++old_p;
                  ++old_p;
                  break;
                  break;
                case 'Q':       /* Qualified name.  */
                case 'Q':       /* Qualified name.  */
                  integralp = TRUE;
                  integralp = TRUE;
                  done = TRUE;
                  done = TRUE;
                  break;
                  break;
                case 'T':       /* Remembered type.  */
                case 'T':       /* Remembered type.  */
                  abort ();
                  abort ();
                case 'v':       /* Void.  */
                case 'v':       /* Void.  */
                  abort ();
                  abort ();
                case 'x':       /* Long long.  */
                case 'x':       /* Long long.  */
                case 'l':       /* Long.  */
                case 'l':       /* Long.  */
                case 'i':       /* Int.  */
                case 'i':       /* Int.  */
                case 's':       /* Short.  */
                case 's':       /* Short.  */
                case 'w':       /* Wchar_t.  */
                case 'w':       /* Wchar_t.  */
                  integralp = TRUE;
                  integralp = TRUE;
                  done = TRUE;
                  done = TRUE;
                  break;
                  break;
                case 'b':       /* Bool.  */
                case 'b':       /* Bool.  */
                  boolp = TRUE;
                  boolp = TRUE;
                  done = TRUE;
                  done = TRUE;
                  break;
                  break;
                case 'c':       /* Char.  */
                case 'c':       /* Char.  */
                  charp = TRUE;
                  charp = TRUE;
                  done = TRUE;
                  done = TRUE;
                  break;
                  break;
                case 'r':       /* Long double.  */
                case 'r':       /* Long double.  */
                case 'd':       /* Double.  */
                case 'd':       /* Double.  */
                case 'f':       /* Float.  */
                case 'f':       /* Float.  */
                  realp = TRUE;
                  realp = TRUE;
                  done = TRUE;
                  done = TRUE;
                  break;
                  break;
                default:
                default:
                  /* Assume it's a user defined integral type.  */
                  /* Assume it's a user defined integral type.  */
                  integralp = TRUE;
                  integralp = TRUE;
                  done = TRUE;
                  done = TRUE;
                  break;
                  break;
                }
                }
            }
            }
 
 
          if (integralp)
          if (integralp)
            {
            {
              if (**pp == 'm')
              if (**pp == 'm')
                ++*pp;
                ++*pp;
              while (ISDIGIT (**pp))
              while (ISDIGIT (**pp))
                ++*pp;
                ++*pp;
            }
            }
          else if (charp)
          else if (charp)
            {
            {
              unsigned int val;
              unsigned int val;
 
 
              if (**pp == 'm')
              if (**pp == 'm')
                ++*pp;
                ++*pp;
              val = stab_demangle_count (pp);
              val = stab_demangle_count (pp);
              if (val == 0)
              if (val == 0)
                {
                {
                  stab_bad_demangle (orig);
                  stab_bad_demangle (orig);
                  return FALSE;
                  return FALSE;
                }
                }
            }
            }
          else if (boolp)
          else if (boolp)
            {
            {
              unsigned int val;
              unsigned int val;
 
 
              val = stab_demangle_count (pp);
              val = stab_demangle_count (pp);
              if (val != 0 && val != 1)
              if (val != 0 && val != 1)
                {
                {
                  stab_bad_demangle (orig);
                  stab_bad_demangle (orig);
                  return FALSE;
                  return FALSE;
                }
                }
            }
            }
          else if (realp)
          else if (realp)
            {
            {
              if (**pp == 'm')
              if (**pp == 'm')
                ++*pp;
                ++*pp;
              while (ISDIGIT (**pp))
              while (ISDIGIT (**pp))
                ++*pp;
                ++*pp;
              if (**pp == '.')
              if (**pp == '.')
                {
                {
                  ++*pp;
                  ++*pp;
                  while (ISDIGIT (**pp))
                  while (ISDIGIT (**pp))
                    ++*pp;
                    ++*pp;
                }
                }
              if (**pp == 'e')
              if (**pp == 'e')
                {
                {
                  ++*pp;
                  ++*pp;
                  while (ISDIGIT (**pp))
                  while (ISDIGIT (**pp))
                    ++*pp;
                    ++*pp;
                }
                }
            }
            }
          else if (pointerp)
          else if (pointerp)
            {
            {
              unsigned int len;
              unsigned int len;
 
 
              len = stab_demangle_count (pp);
              len = stab_demangle_count (pp);
              if (len == 0)
              if (len == 0)
                {
                {
                  stab_bad_demangle (orig);
                  stab_bad_demangle (orig);
                  return FALSE;
                  return FALSE;
                }
                }
              *pp += len;
              *pp += len;
            }
            }
        }
        }
    }
    }
 
 
  /* We can translate this to a string fairly easily by invoking the
  /* We can translate this to a string fairly easily by invoking the
     regular demangling routine.  */
     regular demangling routine.  */
  if (pname != NULL)
  if (pname != NULL)
    {
    {
      char *s1, *s2, *s3, *s4 = NULL;
      char *s1, *s2, *s3, *s4 = NULL;
      char *from, *to;
      char *from, *to;
 
 
      s1 = savestring (orig, *pp - orig);
      s1 = savestring (orig, *pp - orig);
 
 
      s2 = concat ("NoSuchStrinG__", s1, (const char *) NULL);
      s2 = concat ("NoSuchStrinG__", s1, (const char *) NULL);
 
 
      free (s1);
      free (s1);
 
 
      s3 = cplus_demangle (s2, DMGL_ANSI);
      s3 = cplus_demangle (s2, DMGL_ANSI);
 
 
      free (s2);
      free (s2);
 
 
      if (s3 != NULL)
      if (s3 != NULL)
        s4 = strstr (s3, "::NoSuchStrinG");
        s4 = strstr (s3, "::NoSuchStrinG");
      if (s3 == NULL || s4 == NULL)
      if (s3 == NULL || s4 == NULL)
        {
        {
          stab_bad_demangle (orig);
          stab_bad_demangle (orig);
          if (s3 != NULL)
          if (s3 != NULL)
            free (s3);
            free (s3);
          return FALSE;
          return FALSE;
        }
        }
 
 
      /* Eliminating all spaces, except those between > characters,
      /* Eliminating all spaces, except those between > characters,
         makes it more likely that the demangled name will match the
         makes it more likely that the demangled name will match the
         name which g++ used as the structure name.  */
         name which g++ used as the structure name.  */
      for (from = to = s3; from != s4; ++from)
      for (from = to = s3; from != s4; ++from)
        if (*from != ' '
        if (*from != ' '
            || (from[1] == '>' && from > s3 && from[-1] == '>'))
            || (from[1] == '>' && from > s3 && from[-1] == '>'))
          *to++ = *from;
          *to++ = *from;
 
 
      *pname = savestring (s3, to - s3);
      *pname = savestring (s3, to - s3);
 
 
      free (s3);
      free (s3);
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Demangle a class name.  */
/* Demangle a class name.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_class (struct stab_demangle_info *minfo ATTRIBUTE_UNUSED,
stab_demangle_class (struct stab_demangle_info *minfo ATTRIBUTE_UNUSED,
                     const char **pp, const char **pstart)
                     const char **pp, const char **pstart)
{
{
  const char *orig;
  const char *orig;
  unsigned int n;
  unsigned int n;
 
 
  orig = *pp;
  orig = *pp;
 
 
  n = stab_demangle_count (pp);
  n = stab_demangle_count (pp);
  if (strlen (*pp) < n)
  if (strlen (*pp) < n)
    {
    {
      stab_bad_demangle (orig);
      stab_bad_demangle (orig);
      return FALSE;
      return FALSE;
    }
    }
 
 
  if (pstart != NULL)
  if (pstart != NULL)
    *pstart = *pp;
    *pstart = *pp;
 
 
  *pp += n;
  *pp += n;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Demangle function arguments.  If the pargs argument is not NULL, it
/* Demangle function arguments.  If the pargs argument is not NULL, it
   is set to a NULL terminated array holding the arguments.  */
   is set to a NULL terminated array holding the arguments.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_args (struct stab_demangle_info *minfo, const char **pp,
stab_demangle_args (struct stab_demangle_info *minfo, const char **pp,
                    debug_type **pargs, bfd_boolean *pvarargs)
                    debug_type **pargs, bfd_boolean *pvarargs)
{
{
  const char *orig;
  const char *orig;
  unsigned int alloc, count;
  unsigned int alloc, count;
 
 
  orig = *pp;
  orig = *pp;
 
 
  alloc = 10;
  alloc = 10;
  if (pargs != NULL)
  if (pargs != NULL)
    {
    {
      *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs);
      *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs);
      *pvarargs = FALSE;
      *pvarargs = FALSE;
    }
    }
  count = 0;
  count = 0;
 
 
  while (**pp != '_' && **pp != '\0' && **pp != 'e')
  while (**pp != '_' && **pp != '\0' && **pp != 'e')
    {
    {
      if (**pp == 'N' || **pp == 'T')
      if (**pp == 'N' || **pp == 'T')
        {
        {
          char temptype;
          char temptype;
          unsigned int r, t;
          unsigned int r, t;
 
 
          temptype = **pp;
          temptype = **pp;
          ++*pp;
          ++*pp;
 
 
          if (temptype == 'T')
          if (temptype == 'T')
            r = 1;
            r = 1;
          else
          else
            {
            {
              if (! stab_demangle_get_count (pp, &r))
              if (! stab_demangle_get_count (pp, &r))
                {
                {
                  stab_bad_demangle (orig);
                  stab_bad_demangle (orig);
                  return FALSE;
                  return FALSE;
                }
                }
            }
            }
 
 
          if (! stab_demangle_get_count (pp, &t))
          if (! stab_demangle_get_count (pp, &t))
            {
            {
              stab_bad_demangle (orig);
              stab_bad_demangle (orig);
              return FALSE;
              return FALSE;
            }
            }
 
 
          if (t >= minfo->typestring_count)
          if (t >= minfo->typestring_count)
            {
            {
              stab_bad_demangle (orig);
              stab_bad_demangle (orig);
              return FALSE;
              return FALSE;
            }
            }
          while (r-- > 0)
          while (r-- > 0)
            {
            {
              const char *tem;
              const char *tem;
 
 
              tem = minfo->typestrings[t].typestring;
              tem = minfo->typestrings[t].typestring;
              if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc))
              if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc))
                return FALSE;
                return FALSE;
            }
            }
        }
        }
      else
      else
        {
        {
          if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc))
          if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc))
            return FALSE;
            return FALSE;
        }
        }
    }
    }
 
 
  if (pargs != NULL)
  if (pargs != NULL)
    (*pargs)[count] = DEBUG_TYPE_NULL;
    (*pargs)[count] = DEBUG_TYPE_NULL;
 
 
  if (**pp == 'e')
  if (**pp == 'e')
    {
    {
      if (pargs != NULL)
      if (pargs != NULL)
        *pvarargs = TRUE;
        *pvarargs = TRUE;
      ++*pp;
      ++*pp;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Demangle a single argument.  */
/* Demangle a single argument.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_arg (struct stab_demangle_info *minfo, const char **pp,
stab_demangle_arg (struct stab_demangle_info *minfo, const char **pp,
                   debug_type **pargs, unsigned int *pcount,
                   debug_type **pargs, unsigned int *pcount,
                   unsigned int *palloc)
                   unsigned int *palloc)
{
{
  const char *start;
  const char *start;
  debug_type type;
  debug_type type;
 
 
  start = *pp;
  start = *pp;
  if (! stab_demangle_type (minfo, pp,
  if (! stab_demangle_type (minfo, pp,
                            pargs == NULL ? (debug_type *) NULL : &type)
                            pargs == NULL ? (debug_type *) NULL : &type)
      || ! stab_demangle_remember_type (minfo, start, *pp - start))
      || ! stab_demangle_remember_type (minfo, start, *pp - start))
    return FALSE;
    return FALSE;
 
 
  if (pargs != NULL)
  if (pargs != NULL)
    {
    {
      if (type == DEBUG_TYPE_NULL)
      if (type == DEBUG_TYPE_NULL)
        return FALSE;
        return FALSE;
 
 
      if (*pcount + 1 >= *palloc)
      if (*pcount + 1 >= *palloc)
        {
        {
          *palloc += 10;
          *palloc += 10;
          *pargs = ((debug_type *)
          *pargs = ((debug_type *)
                    xrealloc (*pargs, *palloc * sizeof **pargs));
                    xrealloc (*pargs, *palloc * sizeof **pargs));
        }
        }
      (*pargs)[*pcount] = type;
      (*pargs)[*pcount] = type;
      ++*pcount;
      ++*pcount;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Demangle a type.  If the ptype argument is not NULL, *ptype is set
/* Demangle a type.  If the ptype argument is not NULL, *ptype is set
   to the newly allocated type.  */
   to the newly allocated type.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_type (struct stab_demangle_info *minfo, const char **pp,
stab_demangle_type (struct stab_demangle_info *minfo, const char **pp,
                    debug_type *ptype)
                    debug_type *ptype)
{
{
  const char *orig;
  const char *orig;
 
 
  orig = *pp;
  orig = *pp;
 
 
  switch (**pp)
  switch (**pp)
    {
    {
    case 'P':
    case 'P':
    case 'p':
    case 'p':
      /* A pointer type.  */
      /* A pointer type.  */
      ++*pp;
      ++*pp;
      if (! stab_demangle_type (minfo, pp, ptype))
      if (! stab_demangle_type (minfo, pp, ptype))
        return FALSE;
        return FALSE;
      if (ptype != NULL)
      if (ptype != NULL)
        *ptype = debug_make_pointer_type (minfo->dhandle, *ptype);
        *ptype = debug_make_pointer_type (minfo->dhandle, *ptype);
      break;
      break;
 
 
    case 'R':
    case 'R':
      /* A reference type.  */
      /* A reference type.  */
      ++*pp;
      ++*pp;
      if (! stab_demangle_type (minfo, pp, ptype))
      if (! stab_demangle_type (minfo, pp, ptype))
        return FALSE;
        return FALSE;
      if (ptype != NULL)
      if (ptype != NULL)
        *ptype = debug_make_reference_type (minfo->dhandle, *ptype);
        *ptype = debug_make_reference_type (minfo->dhandle, *ptype);
      break;
      break;
 
 
    case 'A':
    case 'A':
      /* An array.  */
      /* An array.  */
      {
      {
        unsigned long high;
        unsigned long high;
 
 
        ++*pp;
        ++*pp;
        high = 0;
        high = 0;
        while (**pp != '\0' && **pp != '_')
        while (**pp != '\0' && **pp != '_')
          {
          {
            if (! ISDIGIT (**pp))
            if (! ISDIGIT (**pp))
              {
              {
                stab_bad_demangle (orig);
                stab_bad_demangle (orig);
                return FALSE;
                return FALSE;
              }
              }
            high *= 10;
            high *= 10;
            high += **pp - '0';
            high += **pp - '0';
            ++*pp;
            ++*pp;
          }
          }
        if (**pp != '_')
        if (**pp != '_')
          {
          {
            stab_bad_demangle (orig);
            stab_bad_demangle (orig);
            return FALSE;
            return FALSE;
          }
          }
        ++*pp;
        ++*pp;
 
 
        if (! stab_demangle_type (minfo, pp, ptype))
        if (! stab_demangle_type (minfo, pp, ptype))
          return FALSE;
          return FALSE;
        if (ptype != NULL)
        if (ptype != NULL)
          {
          {
            debug_type int_type;
            debug_type int_type;
 
 
            int_type = debug_find_named_type (minfo->dhandle, "int");
            int_type = debug_find_named_type (minfo->dhandle, "int");
            if (int_type == NULL)
            if (int_type == NULL)
              int_type = debug_make_int_type (minfo->dhandle, 4, FALSE);
              int_type = debug_make_int_type (minfo->dhandle, 4, FALSE);
            *ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type,
            *ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type,
                                            0, high, FALSE);
                                            0, high, FALSE);
          }
          }
      }
      }
      break;
      break;
 
 
    case 'T':
    case 'T':
      /* A back reference to a remembered type.  */
      /* A back reference to a remembered type.  */
      {
      {
        unsigned int i;
        unsigned int i;
        const char *p;
        const char *p;
 
 
        ++*pp;
        ++*pp;
        if (! stab_demangle_get_count (pp, &i))
        if (! stab_demangle_get_count (pp, &i))
          {
          {
            stab_bad_demangle (orig);
            stab_bad_demangle (orig);
            return FALSE;
            return FALSE;
          }
          }
        if (i >= minfo->typestring_count)
        if (i >= minfo->typestring_count)
          {
          {
            stab_bad_demangle (orig);
            stab_bad_demangle (orig);
            return FALSE;
            return FALSE;
          }
          }
        p = minfo->typestrings[i].typestring;
        p = minfo->typestrings[i].typestring;
        if (! stab_demangle_type (minfo, &p, ptype))
        if (! stab_demangle_type (minfo, &p, ptype))
          return FALSE;
          return FALSE;
      }
      }
      break;
      break;
 
 
    case 'F':
    case 'F':
      /* A function.  */
      /* A function.  */
      {
      {
        debug_type *args;
        debug_type *args;
        bfd_boolean varargs;
        bfd_boolean varargs;
 
 
        ++*pp;
        ++*pp;
        if (! stab_demangle_args (minfo, pp,
        if (! stab_demangle_args (minfo, pp,
                                  (ptype == NULL
                                  (ptype == NULL
                                   ? (debug_type **) NULL
                                   ? (debug_type **) NULL
                                   : &args),
                                   : &args),
                                  (ptype == NULL
                                  (ptype == NULL
                                   ? (bfd_boolean *) NULL
                                   ? (bfd_boolean *) NULL
                                   : &varargs)))
                                   : &varargs)))
          return FALSE;
          return FALSE;
        if (**pp != '_')
        if (**pp != '_')
          {
          {
            /* cplus_demangle will accept a function without a return
            /* cplus_demangle will accept a function without a return
               type, but I don't know when that will happen, or what
               type, but I don't know when that will happen, or what
               to do if it does.  */
               to do if it does.  */
            stab_bad_demangle (orig);
            stab_bad_demangle (orig);
            return FALSE;
            return FALSE;
          }
          }
        ++*pp;
        ++*pp;
        if (! stab_demangle_type (minfo, pp, ptype))
        if (! stab_demangle_type (minfo, pp, ptype))
          return FALSE;
          return FALSE;
        if (ptype != NULL)
        if (ptype != NULL)
          *ptype = debug_make_function_type (minfo->dhandle, *ptype, args,
          *ptype = debug_make_function_type (minfo->dhandle, *ptype, args,
                                             varargs);
                                             varargs);
 
 
      }
      }
      break;
      break;
 
 
    case 'M':
    case 'M':
    case 'O':
    case 'O':
      {
      {
        bfd_boolean memberp;
        bfd_boolean memberp;
        debug_type class_type = DEBUG_TYPE_NULL;
        debug_type class_type = DEBUG_TYPE_NULL;
        debug_type *args;
        debug_type *args;
        bfd_boolean varargs;
        bfd_boolean varargs;
        unsigned int n;
        unsigned int n;
        const char *name;
        const char *name;
 
 
        memberp = **pp == 'M';
        memberp = **pp == 'M';
        args = NULL;
        args = NULL;
        varargs = FALSE;
        varargs = FALSE;
 
 
        ++*pp;
        ++*pp;
        if (ISDIGIT (**pp))
        if (ISDIGIT (**pp))
          {
          {
            n = stab_demangle_count (pp);
            n = stab_demangle_count (pp);
            if (strlen (*pp) < n)
            if (strlen (*pp) < n)
              {
              {
                stab_bad_demangle (orig);
                stab_bad_demangle (orig);
                return FALSE;
                return FALSE;
              }
              }
            name = *pp;
            name = *pp;
            *pp += n;
            *pp += n;
 
 
            if (ptype != NULL)
            if (ptype != NULL)
              {
              {
                class_type = stab_find_tagged_type (minfo->dhandle,
                class_type = stab_find_tagged_type (minfo->dhandle,
                                                    minfo->info,
                                                    minfo->info,
                                                    name, (int) n,
                                                    name, (int) n,
                                                    DEBUG_KIND_CLASS);
                                                    DEBUG_KIND_CLASS);
                if (class_type == DEBUG_TYPE_NULL)
                if (class_type == DEBUG_TYPE_NULL)
                  return FALSE;
                  return FALSE;
              }
              }
          }
          }
        else if (**pp == 'Q')
        else if (**pp == 'Q')
          {
          {
            if (! stab_demangle_qualified (minfo, pp,
            if (! stab_demangle_qualified (minfo, pp,
                                           (ptype == NULL
                                           (ptype == NULL
                                            ? (debug_type *) NULL
                                            ? (debug_type *) NULL
                                            : &class_type)))
                                            : &class_type)))
              return FALSE;
              return FALSE;
          }
          }
        else
        else
          {
          {
            stab_bad_demangle (orig);
            stab_bad_demangle (orig);
            return FALSE;
            return FALSE;
          }
          }
 
 
        if (memberp)
        if (memberp)
          {
          {
            if (**pp == 'C')
            if (**pp == 'C')
              {
              {
                ++*pp;
                ++*pp;
              }
              }
            else if (**pp == 'V')
            else if (**pp == 'V')
              {
              {
                ++*pp;
                ++*pp;
              }
              }
            if (**pp != 'F')
            if (**pp != 'F')
              {
              {
                stab_bad_demangle (orig);
                stab_bad_demangle (orig);
                return FALSE;
                return FALSE;
              }
              }
            ++*pp;
            ++*pp;
            if (! stab_demangle_args (minfo, pp,
            if (! stab_demangle_args (minfo, pp,
                                      (ptype == NULL
                                      (ptype == NULL
                                       ? (debug_type **) NULL
                                       ? (debug_type **) NULL
                                       : &args),
                                       : &args),
                                      (ptype == NULL
                                      (ptype == NULL
                                       ? (bfd_boolean *) NULL
                                       ? (bfd_boolean *) NULL
                                       : &varargs)))
                                       : &varargs)))
              return FALSE;
              return FALSE;
          }
          }
 
 
        if (**pp != '_')
        if (**pp != '_')
          {
          {
            stab_bad_demangle (orig);
            stab_bad_demangle (orig);
            return FALSE;
            return FALSE;
          }
          }
        ++*pp;
        ++*pp;
 
 
        if (! stab_demangle_type (minfo, pp, ptype))
        if (! stab_demangle_type (minfo, pp, ptype))
          return FALSE;
          return FALSE;
 
 
        if (ptype != NULL)
        if (ptype != NULL)
          {
          {
            if (! memberp)
            if (! memberp)
              *ptype = debug_make_offset_type (minfo->dhandle, class_type,
              *ptype = debug_make_offset_type (minfo->dhandle, class_type,
                                               *ptype);
                                               *ptype);
            else
            else
              {
              {
                /* FIXME: We have no way to record constp or
                /* FIXME: We have no way to record constp or
                   volatilep.  */
                   volatilep.  */
                *ptype = debug_make_method_type (minfo->dhandle, *ptype,
                *ptype = debug_make_method_type (minfo->dhandle, *ptype,
                                                 class_type, args, varargs);
                                                 class_type, args, varargs);
              }
              }
          }
          }
      }
      }
      break;
      break;
 
 
    case 'G':
    case 'G':
      ++*pp;
      ++*pp;
      if (! stab_demangle_type (minfo, pp, ptype))
      if (! stab_demangle_type (minfo, pp, ptype))
        return FALSE;
        return FALSE;
      break;
      break;
 
 
    case 'C':
    case 'C':
      ++*pp;
      ++*pp;
      if (! stab_demangle_type (minfo, pp, ptype))
      if (! stab_demangle_type (minfo, pp, ptype))
        return FALSE;
        return FALSE;
      if (ptype != NULL)
      if (ptype != NULL)
        *ptype = debug_make_const_type (minfo->dhandle, *ptype);
        *ptype = debug_make_const_type (minfo->dhandle, *ptype);
      break;
      break;
 
 
    case 'Q':
    case 'Q':
      {
      {
        if (! stab_demangle_qualified (minfo, pp, ptype))
        if (! stab_demangle_qualified (minfo, pp, ptype))
          return FALSE;
          return FALSE;
      }
      }
      break;
      break;
 
 
    default:
    default:
      if (! stab_demangle_fund_type (minfo, pp, ptype))
      if (! stab_demangle_fund_type (minfo, pp, ptype))
        return FALSE;
        return FALSE;
      break;
      break;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Demangle a fundamental type.  If the ptype argument is not NULL,
/* Demangle a fundamental type.  If the ptype argument is not NULL,
   *ptype is set to the newly allocated type.  */
   *ptype is set to the newly allocated type.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_fund_type (struct stab_demangle_info *minfo, const char **pp,
stab_demangle_fund_type (struct stab_demangle_info *minfo, const char **pp,
                         debug_type *ptype)
                         debug_type *ptype)
{
{
  const char *orig;
  const char *orig;
  bfd_boolean constp, volatilep, unsignedp, signedp;
  bfd_boolean constp, volatilep, unsignedp, signedp;
  bfd_boolean done;
  bfd_boolean done;
 
 
  orig = *pp;
  orig = *pp;
 
 
  constp = FALSE;
  constp = FALSE;
  volatilep = FALSE;
  volatilep = FALSE;
  unsignedp = FALSE;
  unsignedp = FALSE;
  signedp = FALSE;
  signedp = FALSE;
 
 
  done = FALSE;
  done = FALSE;
  while (! done)
  while (! done)
    {
    {
      switch (**pp)
      switch (**pp)
        {
        {
        case 'C':
        case 'C':
          constp = TRUE;
          constp = TRUE;
          ++*pp;
          ++*pp;
          break;
          break;
 
 
        case 'U':
        case 'U':
          unsignedp = TRUE;
          unsignedp = TRUE;
          ++*pp;
          ++*pp;
          break;
          break;
 
 
        case 'S':
        case 'S':
          signedp = TRUE;
          signedp = TRUE;
          ++*pp;
          ++*pp;
          break;
          break;
 
 
        case 'V':
        case 'V':
          volatilep = TRUE;
          volatilep = TRUE;
          ++*pp;
          ++*pp;
          break;
          break;
 
 
        default:
        default:
          done = TRUE;
          done = TRUE;
          break;
          break;
        }
        }
    }
    }
 
 
  switch (**pp)
  switch (**pp)
    {
    {
    case '\0':
    case '\0':
    case '_':
    case '_':
      /* cplus_demangle permits this, but I don't know what it means.  */
      /* cplus_demangle permits this, but I don't know what it means.  */
      stab_bad_demangle (orig);
      stab_bad_demangle (orig);
      break;
      break;
 
 
    case 'v': /* void */
    case 'v': /* void */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle, "void");
          *ptype = debug_find_named_type (minfo->dhandle, "void");
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_void_type (minfo->dhandle);
            *ptype = debug_make_void_type (minfo->dhandle);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 'x': /* long long */
    case 'x': /* long long */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle,
          *ptype = debug_find_named_type (minfo->dhandle,
                                          (unsignedp
                                          (unsignedp
                                           ? "long long unsigned int"
                                           ? "long long unsigned int"
                                           : "long long int"));
                                           : "long long int"));
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp);
            *ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 'l': /* long */
    case 'l': /* long */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle,
          *ptype = debug_find_named_type (minfo->dhandle,
                                          (unsignedp
                                          (unsignedp
                                           ? "long unsigned int"
                                           ? "long unsigned int"
                                           : "long int"));
                                           : "long int"));
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
            *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 'i': /* int */
    case 'i': /* int */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle,
          *ptype = debug_find_named_type (minfo->dhandle,
                                          (unsignedp
                                          (unsignedp
                                           ? "unsigned int"
                                           ? "unsigned int"
                                           : "int"));
                                           : "int"));
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
            *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 's': /* short */
    case 's': /* short */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle,
          *ptype = debug_find_named_type (minfo->dhandle,
                                          (unsignedp
                                          (unsignedp
                                           ? "short unsigned int"
                                           ? "short unsigned int"
                                           : "short int"));
                                           : "short int"));
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp);
            *ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 'b': /* bool */
    case 'b': /* bool */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle, "bool");
          *ptype = debug_find_named_type (minfo->dhandle, "bool");
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_bool_type (minfo->dhandle, 4);
            *ptype = debug_make_bool_type (minfo->dhandle, 4);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 'c': /* char */
    case 'c': /* char */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle,
          *ptype = debug_find_named_type (minfo->dhandle,
                                          (unsignedp
                                          (unsignedp
                                           ? "unsigned char"
                                           ? "unsigned char"
                                           : (signedp
                                           : (signedp
                                              ? "signed char"
                                              ? "signed char"
                                              : "char")));
                                              : "char")));
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp);
            *ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 'w': /* wchar_t */
    case 'w': /* wchar_t */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle, "__wchar_t");
          *ptype = debug_find_named_type (minfo->dhandle, "__wchar_t");
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_int_type (minfo->dhandle, 2, TRUE);
            *ptype = debug_make_int_type (minfo->dhandle, 2, TRUE);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 'r': /* long double */
    case 'r': /* long double */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle, "long double");
          *ptype = debug_find_named_type (minfo->dhandle, "long double");
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_float_type (minfo->dhandle, 8);
            *ptype = debug_make_float_type (minfo->dhandle, 8);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 'd': /* double */
    case 'd': /* double */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle, "double");
          *ptype = debug_find_named_type (minfo->dhandle, "double");
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_float_type (minfo->dhandle, 8);
            *ptype = debug_make_float_type (minfo->dhandle, 8);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 'f': /* float */
    case 'f': /* float */
      if (ptype != NULL)
      if (ptype != NULL)
        {
        {
          *ptype = debug_find_named_type (minfo->dhandle, "float");
          *ptype = debug_find_named_type (minfo->dhandle, "float");
          if (*ptype == DEBUG_TYPE_NULL)
          if (*ptype == DEBUG_TYPE_NULL)
            *ptype = debug_make_float_type (minfo->dhandle, 4);
            *ptype = debug_make_float_type (minfo->dhandle, 4);
        }
        }
      ++*pp;
      ++*pp;
      break;
      break;
 
 
    case 'G':
    case 'G':
      ++*pp;
      ++*pp;
      if (! ISDIGIT (**pp))
      if (! ISDIGIT (**pp))
        {
        {
          stab_bad_demangle (orig);
          stab_bad_demangle (orig);
          return FALSE;
          return FALSE;
        }
        }
      /* Fall through.  */
      /* Fall through.  */
    case '0': case '1': case '2': case '3': case '4':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
    case '5': case '6': case '7': case '8': case '9':
      {
      {
        const char *hold;
        const char *hold;
 
 
        if (! stab_demangle_class (minfo, pp, &hold))
        if (! stab_demangle_class (minfo, pp, &hold))
          return FALSE;
          return FALSE;
        if (ptype != NULL)
        if (ptype != NULL)
          {
          {
            char *name;
            char *name;
 
 
            name = savestring (hold, *pp - hold);
            name = savestring (hold, *pp - hold);
            *ptype = debug_find_named_type (minfo->dhandle, name);
            *ptype = debug_find_named_type (minfo->dhandle, name);
            free (name);
            free (name);
            if (*ptype == DEBUG_TYPE_NULL)
            if (*ptype == DEBUG_TYPE_NULL)
              {
              {
                /* FIXME: It is probably incorrect to assume that
                /* FIXME: It is probably incorrect to assume that
                   undefined types are tagged types.  */
                   undefined types are tagged types.  */
                *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
                *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
                                                hold, *pp - hold,
                                                hold, *pp - hold,
                                                DEBUG_KIND_ILLEGAL);
                                                DEBUG_KIND_ILLEGAL);
                if (*ptype == DEBUG_TYPE_NULL)
                if (*ptype == DEBUG_TYPE_NULL)
                  return FALSE;
                  return FALSE;
              }
              }
          }
          }
      }
      }
      break;
      break;
 
 
    case 't':
    case 't':
      {
      {
        char *name;
        char *name;
 
 
        if (! stab_demangle_template (minfo, pp,
        if (! stab_demangle_template (minfo, pp,
                                      ptype != NULL ? &name : NULL))
                                      ptype != NULL ? &name : NULL))
          return FALSE;
          return FALSE;
        if (ptype != NULL)
        if (ptype != NULL)
          {
          {
            *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
            *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
                                            name, strlen (name),
                                            name, strlen (name),
                                            DEBUG_KIND_CLASS);
                                            DEBUG_KIND_CLASS);
            free (name);
            free (name);
            if (*ptype == DEBUG_TYPE_NULL)
            if (*ptype == DEBUG_TYPE_NULL)
              return FALSE;
              return FALSE;
          }
          }
      }
      }
      break;
      break;
 
 
    default:
    default:
      stab_bad_demangle (orig);
      stab_bad_demangle (orig);
      return FALSE;
      return FALSE;
    }
    }
 
 
  if (ptype != NULL)
  if (ptype != NULL)
    {
    {
      if (constp)
      if (constp)
        *ptype = debug_make_const_type (minfo->dhandle, *ptype);
        *ptype = debug_make_const_type (minfo->dhandle, *ptype);
      if (volatilep)
      if (volatilep)
        *ptype = debug_make_volatile_type (minfo->dhandle, *ptype);
        *ptype = debug_make_volatile_type (minfo->dhandle, *ptype);
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Remember a type string in a demangled string.  */
/* Remember a type string in a demangled string.  */
 
 
static bfd_boolean
static bfd_boolean
stab_demangle_remember_type (struct stab_demangle_info *minfo,
stab_demangle_remember_type (struct stab_demangle_info *minfo,
                             const char *p, int len)
                             const char *p, int len)
{
{
  if (minfo->typestring_count >= minfo->typestring_alloc)
  if (minfo->typestring_count >= minfo->typestring_alloc)
    {
    {
      minfo->typestring_alloc += 10;
      minfo->typestring_alloc += 10;
      minfo->typestrings = ((struct stab_demangle_typestring *)
      minfo->typestrings = ((struct stab_demangle_typestring *)
                            xrealloc (minfo->typestrings,
                            xrealloc (minfo->typestrings,
                                      (minfo->typestring_alloc
                                      (minfo->typestring_alloc
                                       * sizeof *minfo->typestrings)));
                                       * sizeof *minfo->typestrings)));
    }
    }
 
 
  minfo->typestrings[minfo->typestring_count].typestring = p;
  minfo->typestrings[minfo->typestring_count].typestring = p;
  minfo->typestrings[minfo->typestring_count].len = (unsigned int) len;
  minfo->typestrings[minfo->typestring_count].len = (unsigned int) len;
  ++minfo->typestring_count;
  ++minfo->typestring_count;
 
 
  return TRUE;
  return TRUE;
}
}


/* Demangle names encoded using the g++ V3 ABI.  The newer versions of
/* Demangle names encoded using the g++ V3 ABI.  The newer versions of
   g++ which use this ABI do not encode ordinary method argument types
   g++ which use this ABI do not encode ordinary method argument types
   in a mangled name; they simply output the argument types.  However,
   in a mangled name; they simply output the argument types.  However,
   for a static method, g++ simply outputs the return type and the
   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.
   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
   Here PHYSNAME is the physical name of the function, and we set the
   variable pointed at by PVARARGS to indicate whether this function
   variable pointed at by PVARARGS to indicate whether this function
   is varargs.  This returns NULL, or a NULL terminated array of
   is varargs.  This returns NULL, or a NULL terminated array of
   argument types.  */
   argument types.  */
 
 
static debug_type *
static debug_type *
stab_demangle_v3_argtypes (void *dhandle, struct stab_handle *info,
stab_demangle_v3_argtypes (void *dhandle, struct stab_handle *info,
                           const char *physname, bfd_boolean *pvarargs)
                           const char *physname, bfd_boolean *pvarargs)
{
{
  struct demangle_component *dc;
  struct demangle_component *dc;
  void *mem;
  void *mem;
  debug_type *pargs;
  debug_type *pargs;
 
 
  dc = cplus_demangle_v3_components (physname, DMGL_PARAMS | DMGL_ANSI, &mem);
  dc = cplus_demangle_v3_components (physname, DMGL_PARAMS | DMGL_ANSI, &mem);
  if (dc == NULL)
  if (dc == NULL)
    {
    {
      stab_bad_demangle (physname);
      stab_bad_demangle (physname);
      return NULL;
      return NULL;
    }
    }
 
 
  /* We expect to see TYPED_NAME, and the right subtree describes the
  /* We expect to see TYPED_NAME, and the right subtree describes the
     function type.  */
     function type.  */
  if (dc->type != DEMANGLE_COMPONENT_TYPED_NAME
  if (dc->type != DEMANGLE_COMPONENT_TYPED_NAME
      || dc->u.s_binary.right->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
      || dc->u.s_binary.right->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
    {
    {
      fprintf (stderr, _("Demangled name is not a function\n"));
      fprintf (stderr, _("Demangled name is not a function\n"));
      free (mem);
      free (mem);
      return NULL;
      return NULL;
    }
    }
 
 
  pargs = stab_demangle_v3_arglist (dhandle, info,
  pargs = stab_demangle_v3_arglist (dhandle, info,
                                    dc->u.s_binary.right->u.s_binary.right,
                                    dc->u.s_binary.right->u.s_binary.right,
                                    pvarargs);
                                    pvarargs);
 
 
  free (mem);
  free (mem);
 
 
  return pargs;
  return pargs;
}
}
 
 
/* Demangle an argument list in a struct demangle_component tree.
/* Demangle an argument list in a struct demangle_component tree.
   Returns a DEBUG_TYPE_NULL terminated array of argument types, and
   Returns a DEBUG_TYPE_NULL terminated array of argument types, and
   sets *PVARARGS to indicate whether this is a varargs function.  */
   sets *PVARARGS to indicate whether this is a varargs function.  */
 
 
static debug_type *
static debug_type *
stab_demangle_v3_arglist (void *dhandle, struct stab_handle *info,
stab_demangle_v3_arglist (void *dhandle, struct stab_handle *info,
                          struct demangle_component *arglist,
                          struct demangle_component *arglist,
                          bfd_boolean *pvarargs)
                          bfd_boolean *pvarargs)
{
{
  struct demangle_component *dc;
  struct demangle_component *dc;
  unsigned int alloc, count;
  unsigned int alloc, count;
  debug_type *pargs;
  debug_type *pargs;
 
 
  alloc = 10;
  alloc = 10;
  pargs = (debug_type *) xmalloc (alloc * sizeof *pargs);
  pargs = (debug_type *) xmalloc (alloc * sizeof *pargs);
  *pvarargs = FALSE;
  *pvarargs = FALSE;
 
 
  count = 0;
  count = 0;
 
 
  for (dc = arglist;
  for (dc = arglist;
       dc != NULL;
       dc != NULL;
       dc = dc->u.s_binary.right)
       dc = dc->u.s_binary.right)
    {
    {
      debug_type arg;
      debug_type arg;
      bfd_boolean varargs;
      bfd_boolean varargs;
 
 
      if (dc->type != DEMANGLE_COMPONENT_ARGLIST)
      if (dc->type != DEMANGLE_COMPONENT_ARGLIST)
        {
        {
          fprintf (stderr, _("Unexpected type in v3 arglist demangling\n"));
          fprintf (stderr, _("Unexpected type in v3 arglist demangling\n"));
          free (pargs);
          free (pargs);
          return NULL;
          return NULL;
        }
        }
 
 
      arg = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left,
      arg = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left,
                                  NULL, &varargs);
                                  NULL, &varargs);
      if (arg == NULL)
      if (arg == NULL)
        {
        {
          if (varargs)
          if (varargs)
            {
            {
              *pvarargs = TRUE;
              *pvarargs = TRUE;
              continue;
              continue;
            }
            }
          free (pargs);
          free (pargs);
          return NULL;
          return NULL;
        }
        }
 
 
      if (count + 1 >= alloc)
      if (count + 1 >= alloc)
        {
        {
          alloc += 10;
          alloc += 10;
          pargs = (debug_type *) xrealloc (pargs, alloc * sizeof *pargs);
          pargs = (debug_type *) xrealloc (pargs, alloc * sizeof *pargs);
        }
        }
 
 
      pargs[count] = arg;
      pargs[count] = arg;
      ++count;
      ++count;
    }
    }
 
 
  pargs[count] = DEBUG_TYPE_NULL;
  pargs[count] = DEBUG_TYPE_NULL;
 
 
  return pargs;
  return pargs;
}
}
 
 
/* Convert a struct demangle_component tree describing an argument
/* Convert a struct demangle_component tree describing an argument
   type into a debug_type.  */
   type into a debug_type.  */
 
 
static debug_type
static debug_type
stab_demangle_v3_arg (void *dhandle, struct stab_handle *info,
stab_demangle_v3_arg (void *dhandle, struct stab_handle *info,
                      struct demangle_component *dc, debug_type context,
                      struct demangle_component *dc, debug_type context,
                      bfd_boolean *pvarargs)
                      bfd_boolean *pvarargs)
{
{
  debug_type dt;
  debug_type dt;
 
 
  if (pvarargs != NULL)
  if (pvarargs != NULL)
    *pvarargs = FALSE;
    *pvarargs = FALSE;
 
 
  switch (dc->type)
  switch (dc->type)
    {
    {
      /* FIXME: These are demangle component types which we probably
      /* FIXME: These are demangle component types which we probably
         need to handle one way or another.  */
         need to handle one way or another.  */
    case DEMANGLE_COMPONENT_LOCAL_NAME:
    case DEMANGLE_COMPONENT_LOCAL_NAME:
    case DEMANGLE_COMPONENT_TYPED_NAME:
    case DEMANGLE_COMPONENT_TYPED_NAME:
    case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
    case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
    case DEMANGLE_COMPONENT_CTOR:
    case DEMANGLE_COMPONENT_CTOR:
    case DEMANGLE_COMPONENT_DTOR:
    case DEMANGLE_COMPONENT_DTOR:
    case DEMANGLE_COMPONENT_JAVA_CLASS:
    case DEMANGLE_COMPONENT_JAVA_CLASS:
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
    case DEMANGLE_COMPONENT_RESTRICT_THIS:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
    case DEMANGLE_COMPONENT_VOLATILE_THIS:
    case DEMANGLE_COMPONENT_CONST_THIS:
    case DEMANGLE_COMPONENT_CONST_THIS:
    case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
    case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
    case DEMANGLE_COMPONENT_COMPLEX:
    case DEMANGLE_COMPONENT_COMPLEX:
    case DEMANGLE_COMPONENT_IMAGINARY:
    case DEMANGLE_COMPONENT_IMAGINARY:
    case DEMANGLE_COMPONENT_VENDOR_TYPE:
    case DEMANGLE_COMPONENT_VENDOR_TYPE:
    case DEMANGLE_COMPONENT_ARRAY_TYPE:
    case DEMANGLE_COMPONENT_ARRAY_TYPE:
    case DEMANGLE_COMPONENT_PTRMEM_TYPE:
    case DEMANGLE_COMPONENT_PTRMEM_TYPE:
    case DEMANGLE_COMPONENT_ARGLIST:
    case DEMANGLE_COMPONENT_ARGLIST:
    default:
    default:
      fprintf (stderr, _("Unrecognized demangle component %d\n"),
      fprintf (stderr, _("Unrecognized demangle component %d\n"),
               (int) dc->type);
               (int) dc->type);
      return NULL;
      return NULL;
 
 
    case DEMANGLE_COMPONENT_NAME:
    case DEMANGLE_COMPONENT_NAME:
      if (context != NULL)
      if (context != NULL)
        {
        {
          const debug_field *fields;
          const debug_field *fields;
 
 
          fields = debug_get_fields (dhandle, context);
          fields = debug_get_fields (dhandle, context);
          if (fields != NULL)
          if (fields != NULL)
            {
            {
              /* Try to find this type by looking through the context
              /* Try to find this type by looking through the context
                 class.  */
                 class.  */
              for (; *fields != DEBUG_FIELD_NULL; fields++)
              for (; *fields != DEBUG_FIELD_NULL; fields++)
                {
                {
                  debug_type ft;
                  debug_type ft;
                  const char *dn;
                  const char *dn;
 
 
                  ft = debug_get_field_type (dhandle, *fields);
                  ft = debug_get_field_type (dhandle, *fields);
                  if (ft == NULL)
                  if (ft == NULL)
                    return NULL;
                    return NULL;
                  dn = debug_get_type_name (dhandle, ft);
                  dn = debug_get_type_name (dhandle, ft);
                  if (dn != NULL
                  if (dn != NULL
                      && (int) strlen (dn) == dc->u.s_name.len
                      && (int) strlen (dn) == dc->u.s_name.len
                      && strncmp (dn, dc->u.s_name.s, dc->u.s_name.len) == 0)
                      && strncmp (dn, dc->u.s_name.s, dc->u.s_name.len) == 0)
                    return ft;
                    return ft;
                }
                }
            }
            }
        }
        }
      return stab_find_tagged_type (dhandle, info, dc->u.s_name.s,
      return stab_find_tagged_type (dhandle, info, dc->u.s_name.s,
                                    dc->u.s_name.len, DEBUG_KIND_ILLEGAL);
                                    dc->u.s_name.len, DEBUG_KIND_ILLEGAL);
 
 
    case DEMANGLE_COMPONENT_QUAL_NAME:
    case DEMANGLE_COMPONENT_QUAL_NAME:
      context = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left,
      context = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left,
                                      context, NULL);
                                      context, NULL);
      if (context == NULL)
      if (context == NULL)
        return NULL;
        return NULL;
      return stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.right,
      return stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.right,
                                   context, NULL);
                                   context, NULL);
 
 
    case DEMANGLE_COMPONENT_TEMPLATE:
    case DEMANGLE_COMPONENT_TEMPLATE:
      {
      {
        char *p;
        char *p;
        size_t alc;
        size_t alc;
 
 
        /* We print this component to get a class name which we can
        /* We print this component to get a class name which we can
           use.  FIXME: This probably won't work if the template uses
           use.  FIXME: This probably won't work if the template uses
           template parameters which refer to an outer template.  */
           template parameters which refer to an outer template.  */
        p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
        p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
        if (p == NULL)
        if (p == NULL)
          {
          {
            fprintf (stderr, _("Failed to print demangled template\n"));
            fprintf (stderr, _("Failed to print demangled template\n"));
            return NULL;
            return NULL;
          }
          }
        dt = stab_find_tagged_type (dhandle, info, p, strlen (p),
        dt = stab_find_tagged_type (dhandle, info, p, strlen (p),
                                    DEBUG_KIND_CLASS);
                                    DEBUG_KIND_CLASS);
        free (p);
        free (p);
        return dt;
        return dt;
      }
      }
 
 
    case DEMANGLE_COMPONENT_SUB_STD:
    case DEMANGLE_COMPONENT_SUB_STD:
      return stab_find_tagged_type (dhandle, info, dc->u.s_string.string,
      return stab_find_tagged_type (dhandle, info, dc->u.s_string.string,
                                    dc->u.s_string.len, DEBUG_KIND_ILLEGAL);
                                    dc->u.s_string.len, DEBUG_KIND_ILLEGAL);
 
 
    case DEMANGLE_COMPONENT_RESTRICT:
    case DEMANGLE_COMPONENT_RESTRICT:
    case DEMANGLE_COMPONENT_VOLATILE:
    case DEMANGLE_COMPONENT_VOLATILE:
    case DEMANGLE_COMPONENT_CONST:
    case DEMANGLE_COMPONENT_CONST:
    case DEMANGLE_COMPONENT_POINTER:
    case DEMANGLE_COMPONENT_POINTER:
    case DEMANGLE_COMPONENT_REFERENCE:
    case DEMANGLE_COMPONENT_REFERENCE:
      dt = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, NULL,
      dt = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, NULL,
                                 NULL);
                                 NULL);
      if (dt == NULL)
      if (dt == NULL)
        return NULL;
        return NULL;
 
 
      switch (dc->type)
      switch (dc->type)
        {
        {
        default:
        default:
          abort ();
          abort ();
        case DEMANGLE_COMPONENT_RESTRICT:
        case DEMANGLE_COMPONENT_RESTRICT:
          /* FIXME: We have no way to represent restrict.  */
          /* FIXME: We have no way to represent restrict.  */
          return dt;
          return dt;
        case DEMANGLE_COMPONENT_VOLATILE:
        case DEMANGLE_COMPONENT_VOLATILE:
          return debug_make_volatile_type (dhandle, dt);
          return debug_make_volatile_type (dhandle, dt);
        case DEMANGLE_COMPONENT_CONST:
        case DEMANGLE_COMPONENT_CONST:
          return debug_make_const_type (dhandle, dt);
          return debug_make_const_type (dhandle, dt);
        case DEMANGLE_COMPONENT_POINTER:
        case DEMANGLE_COMPONENT_POINTER:
          return debug_make_pointer_type (dhandle, dt);
          return debug_make_pointer_type (dhandle, dt);
        case DEMANGLE_COMPONENT_REFERENCE:
        case DEMANGLE_COMPONENT_REFERENCE:
          return debug_make_reference_type (dhandle, dt);
          return debug_make_reference_type (dhandle, dt);
        }
        }
 
 
    case DEMANGLE_COMPONENT_FUNCTION_TYPE:
    case DEMANGLE_COMPONENT_FUNCTION_TYPE:
      {
      {
        debug_type *pargs;
        debug_type *pargs;
        bfd_boolean varargs;
        bfd_boolean varargs;
 
 
        if (dc->u.s_binary.left == NULL)
        if (dc->u.s_binary.left == NULL)
          {
          {
            /* In this case the return type is actually unknown.
            /* In this case the return type is actually unknown.
               However, I'm not sure this will ever arise in practice;
               However, I'm not sure this will ever arise in practice;
               normally an unknown return type would only appear at
               normally an unknown return type would only appear at
               the top level, which is handled above.  */
               the top level, which is handled above.  */
            dt = debug_make_void_type (dhandle);
            dt = debug_make_void_type (dhandle);
          }
          }
        else
        else
          dt = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, NULL,
          dt = stab_demangle_v3_arg (dhandle, info, dc->u.s_binary.left, NULL,
                                     NULL);
                                     NULL);
        if (dt == NULL)
        if (dt == NULL)
          return NULL;
          return NULL;
 
 
        pargs = stab_demangle_v3_arglist (dhandle, info,
        pargs = stab_demangle_v3_arglist (dhandle, info,
                                          dc->u.s_binary.right,
                                          dc->u.s_binary.right,
                                          &varargs);
                                          &varargs);
        if (pargs == NULL)
        if (pargs == NULL)
          return NULL;
          return NULL;
 
 
        return debug_make_function_type (dhandle, dt, pargs, varargs);
        return debug_make_function_type (dhandle, dt, pargs, varargs);
      }
      }
 
 
    case DEMANGLE_COMPONENT_BUILTIN_TYPE:
    case DEMANGLE_COMPONENT_BUILTIN_TYPE:
      {
      {
        char *p;
        char *p;
        size_t alc;
        size_t alc;
        debug_type ret;
        debug_type ret;
 
 
        /* We print this component in order to find out the type name.
        /* We print this component in order to find out the type name.
           FIXME: Should we instead expose the
           FIXME: Should we instead expose the
           demangle_builtin_type_info structure?  */
           demangle_builtin_type_info structure?  */
        p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
        p = cplus_demangle_print (DMGL_PARAMS | DMGL_ANSI, dc, 20, &alc);
        if (p == NULL)
        if (p == NULL)
          {
          {
            fprintf (stderr, _("Couldn't get demangled builtin type\n"));
            fprintf (stderr, _("Couldn't get demangled builtin type\n"));
            return NULL;
            return NULL;
          }
          }
 
 
        /* The mangling is based on the type, but does not itself
        /* The mangling is based on the type, but does not itself
           indicate what the sizes are.  So we have to guess.  */
           indicate what the sizes are.  So we have to guess.  */
        if (strcmp (p, "signed char") == 0)
        if (strcmp (p, "signed char") == 0)
          ret = debug_make_int_type (dhandle, 1, FALSE);
          ret = debug_make_int_type (dhandle, 1, FALSE);
        else if (strcmp (p, "bool") == 0)
        else if (strcmp (p, "bool") == 0)
          ret = debug_make_bool_type (dhandle, 1);
          ret = debug_make_bool_type (dhandle, 1);
        else if (strcmp (p, "char") == 0)
        else if (strcmp (p, "char") == 0)
          ret = debug_make_int_type (dhandle, 1, FALSE);
          ret = debug_make_int_type (dhandle, 1, FALSE);
        else if (strcmp (p, "double") == 0)
        else if (strcmp (p, "double") == 0)
          ret = debug_make_float_type (dhandle, 8);
          ret = debug_make_float_type (dhandle, 8);
        else if (strcmp (p, "long double") == 0)
        else if (strcmp (p, "long double") == 0)
          ret = debug_make_float_type (dhandle, 8);
          ret = debug_make_float_type (dhandle, 8);
        else if (strcmp (p, "float") == 0)
        else if (strcmp (p, "float") == 0)
          ret = debug_make_float_type (dhandle, 4);
          ret = debug_make_float_type (dhandle, 4);
        else if (strcmp (p, "__float128") == 0)
        else if (strcmp (p, "__float128") == 0)
          ret = debug_make_float_type (dhandle, 16);
          ret = debug_make_float_type (dhandle, 16);
        else if (strcmp (p, "unsigned char") == 0)
        else if (strcmp (p, "unsigned char") == 0)
          ret = debug_make_int_type (dhandle, 1, TRUE);
          ret = debug_make_int_type (dhandle, 1, TRUE);
        else if (strcmp (p, "int") == 0)
        else if (strcmp (p, "int") == 0)
          ret = debug_make_int_type (dhandle, 4, FALSE);
          ret = debug_make_int_type (dhandle, 4, FALSE);
        else if (strcmp (p, "unsigned int") == 0)
        else if (strcmp (p, "unsigned int") == 0)
          ret = debug_make_int_type (dhandle, 4, TRUE);
          ret = debug_make_int_type (dhandle, 4, TRUE);
        else if (strcmp (p, "long") == 0)
        else if (strcmp (p, "long") == 0)
          ret = debug_make_int_type (dhandle, 4, FALSE);
          ret = debug_make_int_type (dhandle, 4, FALSE);
        else if (strcmp (p, "unsigned long") == 0)
        else if (strcmp (p, "unsigned long") == 0)
          ret = debug_make_int_type (dhandle, 4, TRUE);
          ret = debug_make_int_type (dhandle, 4, TRUE);
        else if (strcmp (p, "__int128") == 0)
        else if (strcmp (p, "__int128") == 0)
          ret = debug_make_int_type (dhandle, 16, FALSE);
          ret = debug_make_int_type (dhandle, 16, FALSE);
        else if (strcmp (p, "unsigned __int128") == 0)
        else if (strcmp (p, "unsigned __int128") == 0)
          ret = debug_make_int_type (dhandle, 16, TRUE);
          ret = debug_make_int_type (dhandle, 16, TRUE);
        else if (strcmp (p, "short") == 0)
        else if (strcmp (p, "short") == 0)
          ret = debug_make_int_type (dhandle, 2, FALSE);
          ret = debug_make_int_type (dhandle, 2, FALSE);
        else if (strcmp (p, "unsigned short") == 0)
        else if (strcmp (p, "unsigned short") == 0)
          ret = debug_make_int_type (dhandle, 2, TRUE);
          ret = debug_make_int_type (dhandle, 2, TRUE);
        else if (strcmp (p, "void") == 0)
        else if (strcmp (p, "void") == 0)
          ret = debug_make_void_type (dhandle);
          ret = debug_make_void_type (dhandle);
        else if (strcmp (p, "wchar_t") == 0)
        else if (strcmp (p, "wchar_t") == 0)
          ret = debug_make_int_type (dhandle, 4, TRUE);
          ret = debug_make_int_type (dhandle, 4, TRUE);
        else if (strcmp (p, "long long") == 0)
        else if (strcmp (p, "long long") == 0)
          ret = debug_make_int_type (dhandle, 8, FALSE);
          ret = debug_make_int_type (dhandle, 8, FALSE);
        else if (strcmp (p, "unsigned long long") == 0)
        else if (strcmp (p, "unsigned long long") == 0)
          ret = debug_make_int_type (dhandle, 8, TRUE);
          ret = debug_make_int_type (dhandle, 8, TRUE);
        else if (strcmp (p, "...") == 0)
        else if (strcmp (p, "...") == 0)
          {
          {
            if (pvarargs == NULL)
            if (pvarargs == NULL)
              fprintf (stderr, _("Unexpected demangled varargs\n"));
              fprintf (stderr, _("Unexpected demangled varargs\n"));
            else
            else
              *pvarargs = TRUE;
              *pvarargs = TRUE;
            ret = NULL;
            ret = NULL;
          }
          }
        else
        else
          {
          {
            fprintf (stderr, _("Unrecognized demangled builtin type\n"));
            fprintf (stderr, _("Unrecognized demangled builtin type\n"));
            ret = NULL;
            ret = NULL;
          }
          }
 
 
        free (p);
        free (p);
 
 
        return ret;
        return ret;
      }
      }
    }
    }
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.