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