mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	PSTACK, libmysqld and MySQL filesystem UPDATE ... ORDER BY DELETE ... ORDER BY New faster fulltext handling Faster compressed keys
		
			
				
	
	
		
			5083 lines
		
	
	
		
			120 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			5083 lines
		
	
	
		
			120 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* stabs.c -- Parse stabs debugging information
 | 
						||
   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
 | 
						||
   Written by Ian Lance Taylor <ian@cygnus.com>.
 | 
						||
 | 
						||
   This file is part of GNU Binutils.
 | 
						||
 | 
						||
   This program is free software; you can redistribute it and/or modify
 | 
						||
   it under the terms of the GNU General Public License as published by
 | 
						||
   the Free Software Foundation; either version 2 of the License, or
 | 
						||
   (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., 59 Temple Place - Suite 330, Boston, MA
 | 
						||
   02111-1307, USA.  */
 | 
						||
 | 
						||
/* This file contains code which parses stabs debugging information.
 | 
						||
   The organization of this code is based on the gdb stabs reading
 | 
						||
   code.  The job it does is somewhat different, because it is not
 | 
						||
   trying to identify the correct address for anything.  */
 | 
						||
 | 
						||
#include <stdio.h>
 | 
						||
#include <ctype.h>
 | 
						||
 | 
						||
#include <bfd.h>
 | 
						||
#include "bucomm.h"
 | 
						||
#include <libiberty.h>
 | 
						||
#include "demangle.h"
 | 
						||
#include "debug.h"
 | 
						||
#include "budbg.h"
 | 
						||
 | 
						||
/* Meaningless definition needs by aout64.h.  FIXME.  */
 | 
						||
#define BYTES_IN_WORD 4
 | 
						||
 | 
						||
#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.  */
 | 
						||
  boolean sections;
 | 
						||
  /* The symbol table.  */
 | 
						||
  asymbol **syms;
 | 
						||
  /* The number of symbols.  */
 | 
						||
  long symcount;
 | 
						||
  /* The accumulated file name string.  */
 | 
						||
  char *so_string;
 | 
						||
  /* The value of the last N_SO symbol.  */
 | 
						||
  bfd_vma so_value;
 | 
						||
  /* The value of the start of the file, so that we can handle file
 | 
						||
     relative N_LBRAC and N_RBRAC symbols.  */
 | 
						||
  bfd_vma file_start_offset;
 | 
						||
  /* The offset of the start of the function, so that we can handle
 | 
						||
     function relative N_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.  */
 | 
						||
  boolean 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.  */
 | 
						||
  boolean within_function;
 | 
						||
  /* The address of the end of the function, used if we have seen an
 | 
						||
     N_FUN symbol while in a function.  This is -1 if we have not seen
 | 
						||
     an N_FUN (the normal case).  */
 | 
						||
  bfd_vma function_end;
 | 
						||
  /* The depth of block nesting.  */
 | 
						||
  int block_depth;
 | 
						||
  /* List of pending variable definitions.  */
 | 
						||
  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;
 | 
						||
};
 | 
						||
 | 
						||
/* 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;
 | 
						||
  /* 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 char *savestring PARAMS ((const char *, int));
 | 
						||
static bfd_vma parse_number PARAMS ((const char **, boolean *));
 | 
						||
static void bad_stab PARAMS ((const char *));
 | 
						||
static void warn_stab PARAMS ((const char *, const char *));
 | 
						||
static boolean parse_stab_string
 | 
						||
  PARAMS ((PTR, struct stab_handle *, int, int, bfd_vma, const char *));
 | 
						||
static debug_type parse_stab_type
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char *, const char **,
 | 
						||
	   debug_type **));
 | 
						||
static boolean parse_stab_type_number
 | 
						||
  PARAMS ((const char **, int *));
 | 
						||
static debug_type parse_stab_range_type
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char *, const char **,
 | 
						||
	   const int *));
 | 
						||
static debug_type parse_stab_sun_builtin_type PARAMS ((PTR, const char **));
 | 
						||
static debug_type parse_stab_sun_floating_type
 | 
						||
  PARAMS ((PTR, const char **));
 | 
						||
static debug_type parse_stab_enum_type PARAMS ((PTR, const char **));
 | 
						||
static debug_type parse_stab_struct_type
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char *, const char **, boolean,
 | 
						||
	   const int *));
 | 
						||
static boolean parse_stab_baseclasses
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char **, debug_baseclass **));
 | 
						||
static boolean parse_stab_struct_fields
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char **, debug_field **,
 | 
						||
	   boolean *));
 | 
						||
static boolean parse_stab_cpp_abbrev
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char **, debug_field *));
 | 
						||
static boolean parse_stab_one_struct_field
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char **, const char *,
 | 
						||
	   debug_field *, boolean *));
 | 
						||
static boolean parse_stab_members
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char *, const char **,
 | 
						||
	   const int *, debug_method **));
 | 
						||
static debug_type parse_stab_argtypes
 | 
						||
  PARAMS ((PTR, struct stab_handle *, debug_type, const char *, const char *,
 | 
						||
	   debug_type, const char *, boolean, boolean, const char **));
 | 
						||
static boolean parse_stab_tilde_field
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char **, const int *,
 | 
						||
	   debug_type *, boolean *));
 | 
						||
static debug_type parse_stab_array_type
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char **, boolean));
 | 
						||
static void push_bincl PARAMS ((struct stab_handle *, const char *, bfd_vma));
 | 
						||
static const char *pop_bincl PARAMS ((struct stab_handle *));
 | 
						||
static boolean find_excl
 | 
						||
  PARAMS ((struct stab_handle *, const char *, bfd_vma));
 | 
						||
static boolean stab_record_variable
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char *, debug_type,
 | 
						||
	   enum debug_var_kind, bfd_vma));
 | 
						||
static boolean stab_emit_pending_vars PARAMS ((PTR, struct stab_handle *));
 | 
						||
static debug_type *stab_find_slot
 | 
						||
  PARAMS ((struct stab_handle *, const int *));
 | 
						||
static debug_type stab_find_type
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const int *));
 | 
						||
static boolean stab_record_type
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const int *, debug_type));
 | 
						||
static debug_type stab_xcoff_builtin_type
 | 
						||
  PARAMS ((PTR, struct stab_handle *, int));
 | 
						||
static debug_type stab_find_tagged_type
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char *, int,
 | 
						||
	   enum debug_type_kind));
 | 
						||
static debug_type *stab_demangle_argtypes
 | 
						||
  PARAMS ((PTR, struct stab_handle *, const char *, boolean *));
 | 
						||
 | 
						||
/* Save a string in memory.  */
 | 
						||
 | 
						||
static char *
 | 
						||
savestring (start, len)
 | 
						||
     const char *start;
 | 
						||
     int len;
 | 
						||
{
 | 
						||
  char *ret;
 | 
						||
 | 
						||
  ret = (char *) xmalloc (len + 1);
 | 
						||
  memcpy (ret, start, len);
 | 
						||
  ret[len] = '\0';
 | 
						||
  return ret;
 | 
						||
}
 | 
						||
 | 
						||
/* Read a number from a string.  */
 | 
						||
 | 
						||
static bfd_vma
 | 
						||
parse_number (pp, poverflow)
 | 
						||
     const char **pp;
 | 
						||
     boolean *poverflow;
 | 
						||
{
 | 
						||
  unsigned long ul;
 | 
						||
  const char *orig;
 | 
						||
 | 
						||
  if (poverflow != NULL)
 | 
						||
    *poverflow = false;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  errno = 0;
 | 
						||
  ul = strtoul (*pp, (char **) pp, 0);
 | 
						||
  if (ul + 1 != 0 || errno == 0)
 | 
						||
    return (bfd_vma) ul;
 | 
						||
 | 
						||
  /* Note that even though strtoul overflowed, it should have set *pp
 | 
						||
     to the end of the number, which is where we want it.  */
 | 
						||
 | 
						||
  if (sizeof (bfd_vma) > sizeof (unsigned long))
 | 
						||
    {
 | 
						||
      const char *p;
 | 
						||
      boolean neg;
 | 
						||
      int base;
 | 
						||
      bfd_vma over, lastdig;
 | 
						||
      boolean 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 ((unsigned char) d))
 | 
						||
	    d -= '0';
 | 
						||
	  else if (isupper ((unsigned char) d))
 | 
						||
	    d -= 'A';
 | 
						||
	  else if (islower ((unsigned char) 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 (p)
 | 
						||
     const char *p;
 | 
						||
{
 | 
						||
  fprintf (stderr, "Bad stab: %s\n", p);
 | 
						||
}
 | 
						||
 | 
						||
/* Warn about something in a stab string.  */
 | 
						||
 | 
						||
static void
 | 
						||
warn_stab (p, err)
 | 
						||
     const char *p;
 | 
						||
     const char *err;
 | 
						||
{
 | 
						||
  fprintf (stderr, "Warning: %s: %s\n", err, p);
 | 
						||
}
 | 
						||
 | 
						||
/* Create a handle to parse stabs symbols with.  */
 | 
						||
 | 
						||
/*ARGSUSED*/
 | 
						||
PTR
 | 
						||
start_stab (dhandle, abfd, sections, syms, symcount)
 | 
						||
     PTR dhandle;
 | 
						||
     bfd *abfd;
 | 
						||
     boolean sections;
 | 
						||
     asymbol **syms;
 | 
						||
     long symcount;
 | 
						||
{
 | 
						||
  struct stab_handle *ret;
 | 
						||
 | 
						||
  ret = (struct stab_handle *) xmalloc (sizeof *ret);
 | 
						||
  memset (ret, 0, sizeof *ret);
 | 
						||
  ret->abfd = abfd;
 | 
						||
  ret->sections = sections;
 | 
						||
  ret->syms = syms;
 | 
						||
  ret->symcount = symcount;
 | 
						||
  ret->files = 1;
 | 
						||
  ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types);
 | 
						||
  ret->file_types[0] = NULL;
 | 
						||
  ret->function_end = (bfd_vma) -1;
 | 
						||
  return (PTR) ret;
 | 
						||
}
 | 
						||
 | 
						||
/* When we have processed all the stabs information, we need to go
 | 
						||
   through and fill in all the undefined tags.  */
 | 
						||
 | 
						||
boolean
 | 
						||
finish_stab (dhandle, handle)
 | 
						||
     PTR dhandle;
 | 
						||
     PTR handle;
 | 
						||
{
 | 
						||
  struct stab_handle *info = (struct stab_handle *) handle;
 | 
						||
  struct stab_tag *st;
 | 
						||
 | 
						||
  if (info->within_function)
 | 
						||
    {
 | 
						||
      if (! stab_emit_pending_vars (dhandle, info)
 | 
						||
	  || ! debug_end_function (dhandle, info->function_end))
 | 
						||
	return false;
 | 
						||
      info->within_function = false;
 | 
						||
      info->function_end = (bfd_vma) -1;
 | 
						||
    }
 | 
						||
 | 
						||
  for (st = info->tags; st != NULL; st = st->next)
 | 
						||
    {
 | 
						||
      enum debug_type_kind kind;
 | 
						||
 | 
						||
      kind = st->kind;
 | 
						||
      if (kind == DEBUG_KIND_ILLEGAL)
 | 
						||
	kind = DEBUG_KIND_STRUCT;
 | 
						||
      st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind);
 | 
						||
      if (st->slot == DEBUG_TYPE_NULL)
 | 
						||
	return false;
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Handle a single stabs symbol.  */
 | 
						||
 | 
						||
boolean
 | 
						||
parse_stab (dhandle, handle, type, desc, value, string)
 | 
						||
     PTR dhandle;
 | 
						||
     PTR handle;
 | 
						||
     int type;
 | 
						||
     int desc;
 | 
						||
     bfd_vma value;
 | 
						||
     const char *string;
 | 
						||
{
 | 
						||
  struct stab_handle *info = (struct stab_handle *) handle;
 | 
						||
 | 
						||
  /* gcc will emit two N_SO strings per compilation unit, one for the
 | 
						||
     directory name and one for the file name.  We just collect N_SO
 | 
						||
     strings as we see them, and start the new compilation unit when
 | 
						||
     we see a non N_SO symbol.  */
 | 
						||
  if (info->so_string != NULL
 | 
						||
      && (type != N_SO || *string == '\0' || value != info->so_value))
 | 
						||
    {
 | 
						||
      if (! debug_set_filename (dhandle, info->so_string))
 | 
						||
	return false;
 | 
						||
      info->main_filename = info->so_string;
 | 
						||
 | 
						||
      info->gcc_compiled = 0;
 | 
						||
      info->n_opt_found = false;
 | 
						||
 | 
						||
      /* Generally, for stabs in the symbol table, the N_LBRAC and
 | 
						||
	 N_RBRAC symbols are relative to the N_SO symbol value.  */
 | 
						||
      if (! info->sections)
 | 
						||
	info->file_start_offset = info->so_value;
 | 
						||
 | 
						||
      /* We need to reset the mapping from type numbers to types.  We
 | 
						||
	 can't free the old mapping, because of the use of
 | 
						||
	 debug_make_indirect_type.  */
 | 
						||
      info->files = 1;
 | 
						||
      info->file_types = ((struct stab_types **)
 | 
						||
			  xmalloc (sizeof *info->file_types));
 | 
						||
      info->file_types[0] = NULL;
 | 
						||
 | 
						||
      info->so_string = NULL;
 | 
						||
 | 
						||
      /* Now process whatever type we just got.  */
 | 
						||
    }
 | 
						||
 | 
						||
  switch (type)
 | 
						||
    {
 | 
						||
    case N_FN:
 | 
						||
    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 '/', we discard the previously
 | 
						||
         accumulated strings.  */
 | 
						||
      if (info->so_string == NULL)
 | 
						||
	info->so_string = xstrdup (string);
 | 
						||
      else
 | 
						||
	{
 | 
						||
	  char *f;
 | 
						||
 | 
						||
	  f = info->so_string;
 | 
						||
	  if (*string == '/')
 | 
						||
	    info->so_string = xstrdup (string);
 | 
						||
	  else
 | 
						||
	    info->so_string = concat (info->so_string, string,
 | 
						||
				      (const char *) NULL);
 | 
						||
	  free (f);
 | 
						||
	}
 | 
						||
 | 
						||
      info->so_value = value;
 | 
						||
 | 
						||
      break;
 | 
						||
 | 
						||
    case N_SOL:
 | 
						||
      /* Start an include file.  */
 | 
						||
      if (! debug_start_source (dhandle, string))
 | 
						||
	return false;
 | 
						||
      break;
 | 
						||
 | 
						||
    case N_BINCL:
 | 
						||
      /* Start an include file which may be replaced.  */
 | 
						||
      push_bincl (info, string, value);
 | 
						||
      if (! debug_start_source (dhandle, string))
 | 
						||
	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->function_start_offset))
 | 
						||
	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))
 | 
						||
	  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:
 | 
						||
      break;
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Parse the stabs string.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
parse_stab_string (dhandle, info, stabtype, desc, value, string)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     int stabtype;
 | 
						||
     int desc;
 | 
						||
     bfd_vma value;
 | 
						||
     const char *string;
 | 
						||
{
 | 
						||
  const char *p;
 | 
						||
  char *name;
 | 
						||
  int type;
 | 
						||
  debug_type dtype;
 | 
						||
  boolean synonym;
 | 
						||
  unsigned int lineno;
 | 
						||
  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;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  /* GCC 2.x puts the line number in desc.  SunOS apparently puts in
 | 
						||
     the number of bytes occupied by a type or object, which we
 | 
						||
     ignore.  */
 | 
						||
  if (info->gcc_compiled >= 2)
 | 
						||
    lineno = desc;
 | 
						||
  else
 | 
						||
    lineno = 0;
 | 
						||
 | 
						||
  /* FIXME: Sometimes the special C++ names start with '.'.  */
 | 
						||
  name = NULL;
 | 
						||
  if (string[0] == '$')
 | 
						||
    {
 | 
						||
      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 (string, p - string);
 | 
						||
    }
 | 
						||
 | 
						||
  ++p;
 | 
						||
  if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-')
 | 
						||
    type = 'l';
 | 
						||
  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);
 | 
						||
	  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);
 | 
						||
      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);
 | 
						||
      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)
 | 
						||
	      == DEBUG_TYPE_NULL)
 | 
						||
	    return false;
 | 
						||
	}
 | 
						||
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'G':
 | 
						||
      {
 | 
						||
	char leading;
 | 
						||
	long c;
 | 
						||
	asymbol **ps;
 | 
						||
 | 
						||
	/* A global symbol.  The value must be extracted from the
 | 
						||
	   symbol table.  */
 | 
						||
	dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p,
 | 
						||
				 (debug_type **) NULL);
 | 
						||
	if (dtype == DEBUG_TYPE_NULL)
 | 
						||
	  return false;
 | 
						||
	leading = bfd_get_symbol_leading_char (info->abfd);
 | 
						||
	for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
 | 
						||
	  {
 | 
						||
	    const char *n;
 | 
						||
 | 
						||
	    n = bfd_asymbol_name (*ps);
 | 
						||
	    if (leading != '\0' && *n == leading)
 | 
						||
	      ++n;
 | 
						||
	    if (*n == *name && strcmp (n, name) == 0)
 | 
						||
	      break;
 | 
						||
	  }
 | 
						||
	if (c > 0)
 | 
						||
	  value = bfd_asymbol_value (*ps);
 | 
						||
	if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
 | 
						||
				    value))
 | 
						||
	  return false;
 | 
						||
      }
 | 
						||
      break;
 | 
						||
 | 
						||
      /* This case is faked by a conditional above, when there is no
 | 
						||
	 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);
 | 
						||
      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);
 | 
						||
      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);
 | 
						||
	  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)
 | 
						||
		  == 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);
 | 
						||
      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);
 | 
						||
      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);
 | 
						||
      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);
 | 
						||
      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 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);
 | 
						||
      if (dtype == DEBUG_TYPE_NULL)
 | 
						||
	return false;
 | 
						||
      if (name == NULL)
 | 
						||
	return true;
 | 
						||
 | 
						||
      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.  */
 | 
						||
      {
 | 
						||
	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);
 | 
						||
      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);
 | 
						||
      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);
 | 
						||
      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);
 | 
						||
      if (dtype == DEBUG_TYPE_NULL)
 | 
						||
	return false;
 | 
						||
      if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL,
 | 
						||
				  value))
 | 
						||
	return false;
 | 
						||
      break;
 | 
						||
 | 
						||
    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 (dhandle, info, typename, pp, slotp)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char *typename;
 | 
						||
     const char **pp;
 | 
						||
     debug_type **slotp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  int typenums[2];
 | 
						||
  int size;
 | 
						||
  boolean stringp;
 | 
						||
  int descriptor;
 | 
						||
  debug_type dtype;
 | 
						||
 | 
						||
  if (slotp != NULL)
 | 
						||
    *slotp = NULL;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  size = -1;
 | 
						||
  stringp = false;
 | 
						||
 | 
						||
  /* Read type number if present.  The type number may be omitted.
 | 
						||
     for instance in a two-dimensional array declared with type
 | 
						||
     "ar1;1;10;ar1;1;10;4".  */
 | 
						||
  if (! isdigit ((unsigned char) **pp) && **pp != '(' && **pp != '-')
 | 
						||
    {
 | 
						||
      /* '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))
 | 
						||
	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 (info, typenums);
 | 
						||
 | 
						||
      /* Type is being defined here.  */
 | 
						||
      /* Skip the '='.  */
 | 
						||
      ++*pp;
 | 
						||
 | 
						||
      while (**pp == '@')
 | 
						||
	{
 | 
						||
	  const char *p = *pp + 1;
 | 
						||
	  const char *attr;
 | 
						||
 | 
						||
	  if (isdigit ((unsigned char) *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);
 | 
						||
	      if (size <= 0)
 | 
						||
		size = -1;
 | 
						||
	      break;
 | 
						||
 | 
						||
	    case 'S':
 | 
						||
	      stringp = true;
 | 
						||
	      break;
 | 
						||
 | 
						||
	    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;
 | 
						||
	  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;
 | 
						||
	  }
 | 
						||
	while (q1 != NULL && p > q1 && p[1] == ':')
 | 
						||
	  {
 | 
						||
	    q2 = strchr (q1, '>');
 | 
						||
	    if (q2 == NULL || q2 < p)
 | 
						||
	      break;
 | 
						||
	    p += 2;
 | 
						||
	    p = strchr (p, ':');
 | 
						||
	    if (p == NULL)
 | 
						||
	      {
 | 
						||
		bad_stab (orig);
 | 
						||
		return DEBUG_TYPE_NULL;
 | 
						||
	      }
 | 
						||
	  }
 | 
						||
 | 
						||
	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))
 | 
						||
	  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);
 | 
						||
	    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));
 | 
						||
      break;
 | 
						||
 | 
						||
    case '&':
 | 
						||
      /* Reference to another type.  */
 | 
						||
      dtype = (debug_make_reference_type
 | 
						||
	       (dhandle,
 | 
						||
		parse_stab_type (dhandle, info, (const char *) NULL, pp,
 | 
						||
				 (debug_type **) NULL)));
 | 
						||
      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),
 | 
						||
		(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));
 | 
						||
      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)));
 | 
						||
      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);
 | 
						||
	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);
 | 
						||
	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);
 | 
						||
	  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;
 | 
						||
	  unsigned int n;
 | 
						||
	  unsigned int alloc;
 | 
						||
	  boolean varargs;
 | 
						||
 | 
						||
	  domain = parse_stab_type (dhandle, info, (const char *) NULL,
 | 
						||
				    pp, (debug_type **) NULL);
 | 
						||
	  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);
 | 
						||
	  if (return_type == DEBUG_TYPE_NULL)
 | 
						||
	    return DEBUG_TYPE_NULL;
 | 
						||
 | 
						||
	  alloc = 10;
 | 
						||
	  args = (debug_type *) xmalloc (alloc * sizeof *args);
 | 
						||
	  n = 0;
 | 
						||
	  while (**pp != ';')
 | 
						||
	    {
 | 
						||
	      if (**pp != ',')
 | 
						||
		{
 | 
						||
		  bad_stab (orig);
 | 
						||
		  return DEBUG_TYPE_NULL;
 | 
						||
		}
 | 
						||
	      ++*pp;
 | 
						||
 | 
						||
	      if (n + 1 >= alloc)
 | 
						||
		{
 | 
						||
		  alloc += 10;
 | 
						||
		  args = ((debug_type *)
 | 
						||
			  xrealloc ((PTR) args, alloc * sizeof *args));
 | 
						||
		}
 | 
						||
 | 
						||
	      args[n] = parse_stab_type (dhandle, info, (const char *) NULL,
 | 
						||
					 pp, (debug_type **) NULL);
 | 
						||
	      if (args[n] == DEBUG_TYPE_NULL)
 | 
						||
		return DEBUG_TYPE_NULL;
 | 
						||
	      ++n;
 | 
						||
	    }
 | 
						||
	  ++*pp;
 | 
						||
 | 
						||
	  /* If the last type is not void, then this function takes a
 | 
						||
	     variable number of arguments.  Otherwise, we must strip
 | 
						||
	     the void type.  */
 | 
						||
	  if (n == 0
 | 
						||
	      || debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID)
 | 
						||
	    varargs = true;
 | 
						||
	  else
 | 
						||
	    {
 | 
						||
	      --n;
 | 
						||
	      varargs = false;
 | 
						||
	    }
 | 
						||
 | 
						||
	  args[n] = DEBUG_TYPE_NULL;
 | 
						||
 | 
						||
	  dtype = debug_make_method_type (dhandle, return_type, domain, args,
 | 
						||
					  varargs);
 | 
						||
	}
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'r':
 | 
						||
      /* Range type.  */
 | 
						||
      dtype = parse_stab_range_type (dhandle, info, typename, pp, typenums);
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'b':
 | 
						||
      /* FIXME: gdb checks os9k_stabs here.  */
 | 
						||
      /* Sun ACC builtin int type.  */
 | 
						||
      dtype = parse_stab_sun_builtin_type (dhandle, pp);
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'R':
 | 
						||
      /* Sun ACC builtin float type.  */
 | 
						||
      dtype = parse_stab_sun_floating_type (dhandle, pp);
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'e':
 | 
						||
      /* Enumeration type.  */
 | 
						||
      dtype = parse_stab_enum_type (dhandle, pp);
 | 
						||
      break;
 | 
						||
 | 
						||
    case 's':
 | 
						||
    case 'u':
 | 
						||
      /* Struct or union type.  */
 | 
						||
      dtype = parse_stab_struct_type (dhandle, info, typename, pp,
 | 
						||
				      descriptor == 's', typenums);
 | 
						||
      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);
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'S':
 | 
						||
      dtype = debug_make_set_type (dhandle,
 | 
						||
				   parse_stab_type (dhandle, info,
 | 
						||
						    (const char *) NULL,
 | 
						||
						    pp,
 | 
						||
						    (debug_type **) NULL),
 | 
						||
				   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 boolean
 | 
						||
parse_stab_type_number (pp, typenums)
 | 
						||
     const char **pp;
 | 
						||
     int *typenums;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  if (**pp != '(')
 | 
						||
    {
 | 
						||
      typenums[0] = 0;
 | 
						||
      typenums[1] = (int) parse_number (pp, (boolean *) NULL);
 | 
						||
    }
 | 
						||
  else
 | 
						||
    {
 | 
						||
      ++*pp;
 | 
						||
      typenums[0] = (int) parse_number (pp, (boolean *) NULL);
 | 
						||
      if (**pp != ',')
 | 
						||
	{
 | 
						||
	  bad_stab (orig);
 | 
						||
	  return false;
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      typenums[1] = (int) parse_number (pp, (boolean *) NULL);
 | 
						||
      if (**pp != ')')
 | 
						||
	{
 | 
						||
	  bad_stab (orig);
 | 
						||
	  return false;
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Parse a range type.  */
 | 
						||
 | 
						||
static debug_type
 | 
						||
parse_stab_range_type (dhandle, info, typename, pp, typenums)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char *typename;
 | 
						||
     const char **pp;
 | 
						||
     const int *typenums;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  int rangenums[2];
 | 
						||
  boolean self_subrange;
 | 
						||
  debug_type index_type;
 | 
						||
  const char *s2, *s3;
 | 
						||
  bfd_signed_vma n2, n3;
 | 
						||
  boolean ov2, ov3;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  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))
 | 
						||
    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);
 | 
						||
      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);
 | 
						||
  if (**pp != ';')
 | 
						||
    {
 | 
						||
      bad_stab (orig);
 | 
						||
      return DEBUG_TYPE_NULL;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  s3 = *pp;
 | 
						||
  n3 = parse_number (pp, &ov3);
 | 
						||
  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 (strncmp (s2, LLLOW, sizeof LLLOW - 1) == 0
 | 
						||
	      && strncmp (s3, LLHIGH, sizeof LLHIGH - 1) == 0)
 | 
						||
	    return debug_make_int_type (dhandle, 8, false);
 | 
						||
	  if (! ov2
 | 
						||
	      && n2 == 0
 | 
						||
	      && strncmp (s3, ULLHIGH, sizeof ULLHIGH - 1) == 0)
 | 
						||
	    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 (typename != NULL)
 | 
						||
	    {
 | 
						||
	      if (strcmp (typename, "long long int") == 0)
 | 
						||
		return debug_make_int_type (dhandle, 8, false);
 | 
						||
	      else if (strcmp (typename, "long long unsigned int") == 0)
 | 
						||
		return debug_make_int_type (dhandle, 8, true);
 | 
						||
	    }
 | 
						||
	  /* FIXME: The size here really depends upon the target.  */
 | 
						||
	  return debug_make_int_type (dhandle, 4, true);
 | 
						||
	}
 | 
						||
 | 
						||
      /* 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);
 | 
						||
	  /* -1 is used for the upper bound of (4 byte) "unsigned int"
 | 
						||
	     and "unsigned long", and we already checked for that, so
 | 
						||
	     don't need to test for it here.  */
 | 
						||
	}
 | 
						||
      else if (n3 == 0
 | 
						||
	       && n2 < 0
 | 
						||
	       && (self_subrange || n2 == -8))
 | 
						||
	return debug_make_int_type (dhandle, - n2, true);
 | 
						||
      else if (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);
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  /* 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 (dhandle, pp)
 | 
						||
     PTR dhandle;
 | 
						||
     const char **pp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  boolean unsignedp;
 | 
						||
  bfd_vma bits;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  switch (**pp)
 | 
						||
    {
 | 
						||
    case 's':
 | 
						||
      unsignedp = false;
 | 
						||
      break;
 | 
						||
    case 'u':
 | 
						||
      unsignedp = true;
 | 
						||
      break;
 | 
						||
    default:
 | 
						||
      bad_stab (orig);
 | 
						||
      return DEBUG_TYPE_NULL;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  /* For some odd reason, all forms of char put a c here.  This is strange
 | 
						||
     because no other type has this honor.  We can safely ignore this because
 | 
						||
     we actually determine 'char'acterness by the number of bits specified in
 | 
						||
     the descriptor.  */
 | 
						||
  if (**pp == 'c')
 | 
						||
    ++*pp;
 | 
						||
 | 
						||
  /* The first number appears to be the number of bytes occupied
 | 
						||
     by this type, except that unsigned short is 4 instead of 2.
 | 
						||
     Since this information is redundant with the third number,
 | 
						||
     we will ignore it.  */
 | 
						||
  (void) parse_number (pp, (boolean *) NULL);
 | 
						||
  if (**pp != ';')
 | 
						||
    {
 | 
						||
      bad_stab (orig);
 | 
						||
      return DEBUG_TYPE_NULL;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  /* The second number is always 0, so ignore it too. */
 | 
						||
  (void) parse_number (pp, (boolean *) NULL);
 | 
						||
  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, (boolean *) NULL);
 | 
						||
 | 
						||
  /* 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 (dhandle, pp)
 | 
						||
     PTR dhandle;
 | 
						||
     const char **pp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  bfd_vma details;
 | 
						||
  bfd_vma bytes;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  /* The first number has more details about the type, for example
 | 
						||
     FN_COMPLEX.  */
 | 
						||
  details = parse_number (pp, (boolean *) NULL);
 | 
						||
  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, (boolean *) NULL);
 | 
						||
  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 (dhandle, pp)
 | 
						||
     PTR dhandle;
 | 
						||
     const char **pp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  const char **names;
 | 
						||
  bfd_signed_vma *values;
 | 
						||
  unsigned int n;
 | 
						||
  unsigned int alloc;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  /* 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;
 | 
						||
      ++*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 = (const char **) xmalloc (alloc * sizeof *names);
 | 
						||
  values = (bfd_signed_vma *) 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;
 | 
						||
 | 
						||
      name = savestring (*pp, p - *pp);
 | 
						||
 | 
						||
      *pp = p + 1;
 | 
						||
      val = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
 | 
						||
      if (**pp != ',')
 | 
						||
	{
 | 
						||
	  bad_stab (orig);
 | 
						||
	  return DEBUG_TYPE_NULL;
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
 | 
						||
      if (n + 1 >= alloc)
 | 
						||
	{
 | 
						||
	  alloc += 10;
 | 
						||
	  names = ((const char **)
 | 
						||
		   xrealloc ((PTR) names, alloc * sizeof *names));
 | 
						||
	  values = ((bfd_signed_vma *)
 | 
						||
		    xrealloc ((PTR) values, alloc * sizeof *values));
 | 
						||
	}
 | 
						||
 | 
						||
      names[n] = name;
 | 
						||
      values[n] = val;
 | 
						||
      ++n;
 | 
						||
    }
 | 
						||
 | 
						||
  names[n] = NULL;
 | 
						||
  values[n] = 0;
 | 
						||
 | 
						||
  if (**pp == ';')
 | 
						||
    ++*pp;
 | 
						||
 | 
						||
  return debug_make_enum_type (dhandle, names, values);
 | 
						||
}
 | 
						||
 | 
						||
/* Read the description of a structure (or union type) and return an object
 | 
						||
   describing the type.
 | 
						||
 | 
						||
   PP points to a character pointer that points to the next unconsumed token
 | 
						||
   in the the stabs string.  For example, given stabs "A:T4=s4a:1,0,32;;",
 | 
						||
   *PP will point to "4a:1,0,32;;".  */
 | 
						||
 | 
						||
static debug_type
 | 
						||
parse_stab_struct_type (dhandle, info, tagname, pp, structp, typenums)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char *tagname;
 | 
						||
     const char **pp;
 | 
						||
     boolean structp;
 | 
						||
     const int *typenums;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  bfd_vma size;
 | 
						||
  debug_baseclass *baseclasses;
 | 
						||
  debug_field *fields;
 | 
						||
  boolean statics;
 | 
						||
  debug_method *methods;
 | 
						||
  debug_type vptrbase;
 | 
						||
  boolean ownvptr;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  /* Get the size.  */
 | 
						||
  size = parse_number (pp, (boolean *) NULL);
 | 
						||
 | 
						||
  /* Get the other information.  */
 | 
						||
  if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses)
 | 
						||
      || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics)
 | 
						||
      || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods)
 | 
						||
      || ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase,
 | 
						||
				   &ownvptr))
 | 
						||
    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 boolean
 | 
						||
parse_stab_baseclasses (dhandle, info, pp, retp)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char **pp;
 | 
						||
     debug_baseclass **retp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  unsigned int c, i;
 | 
						||
  debug_baseclass *classes;
 | 
						||
 | 
						||
  *retp = NULL;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  if (**pp != '!')
 | 
						||
    {
 | 
						||
      /* No base classes.  */
 | 
						||
      return true;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  c = (unsigned int) parse_number (pp, (boolean *) NULL);
 | 
						||
 | 
						||
  if (**pp != ',')
 | 
						||
    {
 | 
						||
      bad_stab (orig);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp));
 | 
						||
 | 
						||
  for (i = 0; i < c; i++)
 | 
						||
    {
 | 
						||
      boolean virtual;
 | 
						||
      enum debug_visibility visibility;
 | 
						||
      bfd_vma bitpos;
 | 
						||
      debug_type type;
 | 
						||
 | 
						||
      switch (**pp)
 | 
						||
	{
 | 
						||
	case '0':
 | 
						||
	  virtual = false;
 | 
						||
	  break;
 | 
						||
	case '1':
 | 
						||
	  virtual = true;
 | 
						||
	  break;
 | 
						||
	default:
 | 
						||
	  warn_stab (orig, "unknown virtual character for baseclass");
 | 
						||
	  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;
 | 
						||
	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, (boolean *) NULL);
 | 
						||
      if (**pp != ',')
 | 
						||
	{
 | 
						||
	  bad_stab (orig);
 | 
						||
	  return false;
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
 | 
						||
      type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
 | 
						||
			      (debug_type **) NULL);
 | 
						||
      if (type == DEBUG_TYPE_NULL)
 | 
						||
	return false;
 | 
						||
 | 
						||
      classes[i] = debug_make_baseclass (dhandle, type, bitpos, 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 boolean
 | 
						||
parse_stab_struct_fields (dhandle, info, pp, retp, staticsp)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char **pp;
 | 
						||
     debug_field **retp;
 | 
						||
     boolean *staticsp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  const char *p;
 | 
						||
  debug_field *fields;
 | 
						||
  unsigned int c;
 | 
						||
  unsigned int alloc;
 | 
						||
 | 
						||
  *retp = NULL;
 | 
						||
  *staticsp = false;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  c = 0;
 | 
						||
  alloc = 10;
 | 
						||
  fields = (debug_field *) 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 = ((debug_field *)
 | 
						||
		    xrealloc ((PTR) 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))
 | 
						||
	    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);
 | 
						||
	  return false;
 | 
						||
	}
 | 
						||
 | 
						||
      if (p[1] == ':')
 | 
						||
	break;
 | 
						||
 | 
						||
      if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c,
 | 
						||
					 staticsp))
 | 
						||
	return false;
 | 
						||
 | 
						||
      ++c;
 | 
						||
    }
 | 
						||
 | 
						||
  fields[c] = DEBUG_FIELD_NULL;
 | 
						||
 | 
						||
  *retp = fields;
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Special GNU C++ name.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
parse_stab_cpp_abbrev (dhandle, info, pp, retp)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char **pp;
 | 
						||
     debug_field *retp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  int cpp_abbrev;
 | 
						||
  debug_type context;
 | 
						||
  const char *name;
 | 
						||
  const char *typename;
 | 
						||
  debug_type type;
 | 
						||
  bfd_vma bitpos;
 | 
						||
 | 
						||
  *retp = DEBUG_FIELD_NULL;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  if (**pp != 'v')
 | 
						||
    {
 | 
						||
      bad_stab (*pp);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  cpp_abbrev = **pp;
 | 
						||
  ++*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);
 | 
						||
  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 */
 | 
						||
      typename = debug_get_type_name (dhandle, context);
 | 
						||
      if (typename == NULL)
 | 
						||
	{
 | 
						||
	  warn_stab (orig, "unnamed $vb type");
 | 
						||
	  typename = "FOO";
 | 
						||
	}
 | 
						||
      name = concat ("_vb$", typename, (const char *) NULL);
 | 
						||
      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);
 | 
						||
  if (**pp != ',')
 | 
						||
    {
 | 
						||
      bad_stab (orig);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  bitpos = parse_number (pp, (boolean *) NULL);
 | 
						||
  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 boolean
 | 
						||
parse_stab_one_struct_field (dhandle, info, pp, p, retp, staticsp)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char **pp;
 | 
						||
     const char *p;
 | 
						||
     debug_field *retp;
 | 
						||
     boolean *staticsp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  char *name;
 | 
						||
  enum debug_visibility visibility;
 | 
						||
  debug_type type;
 | 
						||
  bfd_vma bitpos;
 | 
						||
  bfd_vma bitsize;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  /* FIXME: gdb checks ARM_DEMANGLING here.  */
 | 
						||
 | 
						||
  name = savestring (*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;
 | 
						||
	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);
 | 
						||
  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 (*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, (boolean *) NULL);
 | 
						||
  if (**pp != ',')
 | 
						||
    {
 | 
						||
      bad_stab (orig);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  bitsize = parse_number (pp, (boolean *) NULL);
 | 
						||
  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 boolean
 | 
						||
parse_stab_members (dhandle, info, tagname, pp, typenums, retp)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char *tagname;
 | 
						||
     const char **pp;
 | 
						||
     const int *typenums;
 | 
						||
     debug_method **retp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  debug_method *methods;
 | 
						||
  unsigned int c;
 | 
						||
  unsigned int alloc;
 | 
						||
 | 
						||
  *retp = NULL;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  alloc = 0;
 | 
						||
  methods = NULL;
 | 
						||
  c = 0;
 | 
						||
 | 
						||
  while (**pp != ';')
 | 
						||
    {
 | 
						||
      const char *p;
 | 
						||
      char *name;
 | 
						||
      debug_method_variant *variants;
 | 
						||
      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 (*pp, p - *pp);
 | 
						||
	  *pp = p + 2;
 | 
						||
	}
 | 
						||
      else
 | 
						||
	{
 | 
						||
	  /* This is a completely wierd 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);
 | 
						||
	      return false;
 | 
						||
	    }
 | 
						||
	  name = savestring (*pp, p - *pp);
 | 
						||
	  *pp = p + 1;
 | 
						||
	}
 | 
						||
 | 
						||
      allocvars = 10;
 | 
						||
      variants = ((debug_method_variant *)
 | 
						||
		  xmalloc (allocvars * sizeof *variants));
 | 
						||
      cvars = 0;
 | 
						||
 | 
						||
      look_ahead_type = DEBUG_TYPE_NULL;
 | 
						||
 | 
						||
      do
 | 
						||
	{
 | 
						||
	  debug_type type;
 | 
						||
	  boolean stub;
 | 
						||
	  char *argtypes;
 | 
						||
	  enum debug_visibility visibility;
 | 
						||
	  boolean constp, volatilep, staticp;
 | 
						||
	  bfd_vma voffset;
 | 
						||
	  debug_type context;
 | 
						||
	  const char *physname;
 | 
						||
	  boolean varargs;
 | 
						||
 | 
						||
	  if (look_ahead_type != DEBUG_TYPE_NULL)
 | 
						||
	    {
 | 
						||
	      /* 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);
 | 
						||
	      if (type == DEBUG_TYPE_NULL)
 | 
						||
		return false;
 | 
						||
	      if (**pp != ':')
 | 
						||
		{
 | 
						||
		  bad_stab (orig);
 | 
						||
		  return false;
 | 
						||
		}
 | 
						||
	    }
 | 
						||
 | 
						||
	  ++*pp;
 | 
						||
	  p = strchr (*pp, ';');
 | 
						||
	  if (p == NULL)
 | 
						||
	    {
 | 
						||
	      bad_stab (orig);
 | 
						||
	      return false;
 | 
						||
	    }
 | 
						||
 | 
						||
	  stub = false;
 | 
						||
	  if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD
 | 
						||
	      && debug_get_parameter_types (dhandle, type, &varargs) == NULL)
 | 
						||
	    stub = true;
 | 
						||
 | 
						||
	  argtypes = savestring (*pp, p - *pp);
 | 
						||
	  *pp = p + 1;
 | 
						||
 | 
						||
	  switch (**pp)
 | 
						||
	    {
 | 
						||
	    case '0':
 | 
						||
	      visibility = DEBUG_VISIBILITY_PRIVATE;
 | 
						||
	      break;
 | 
						||
	    case '1':
 | 
						||
	      visibility = DEBUG_VISIBILITY_PROTECTED;
 | 
						||
	      break;
 | 
						||
	    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 indicies.  */
 | 
						||
	      ++*pp;
 | 
						||
	      voffset = parse_number (pp, (boolean *) NULL);
 | 
						||
	      if (**pp != ';')
 | 
						||
		{
 | 
						||
		  bad_stab (orig);
 | 
						||
		  return false;
 | 
						||
		}
 | 
						||
	      ++*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);
 | 
						||
		    if (**pp == ':')
 | 
						||
		      {
 | 
						||
			/* g++ version 1 overloaded methods.  */
 | 
						||
			context = DEBUG_TYPE_NULL;
 | 
						||
		      }
 | 
						||
		    else
 | 
						||
		      {
 | 
						||
			context = look_ahead_type;
 | 
						||
			look_ahead_type = DEBUG_TYPE_NULL;
 | 
						||
			if (**pp != ';')
 | 
						||
			  {
 | 
						||
			    bad_stab (orig);
 | 
						||
			    return false;
 | 
						||
			  }
 | 
						||
			++*pp;
 | 
						||
		      }
 | 
						||
		  }
 | 
						||
	      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.  */
 | 
						||
	  if (! stub)
 | 
						||
	    physname = argtypes;
 | 
						||
	  else
 | 
						||
	    {
 | 
						||
	      debug_type class_type, return_type;
 | 
						||
 | 
						||
	      class_type = stab_find_type (dhandle, info, typenums);
 | 
						||
	      if (class_type == DEBUG_TYPE_NULL)
 | 
						||
		return false;
 | 
						||
	      return_type = debug_get_return_type (dhandle, type);
 | 
						||
	      if (return_type == DEBUG_TYPE_NULL)
 | 
						||
		{
 | 
						||
		  bad_stab (orig);
 | 
						||
		  return false;
 | 
						||
		}
 | 
						||
	      type = parse_stab_argtypes (dhandle, info, class_type, name,
 | 
						||
					  tagname, return_type, argtypes,
 | 
						||
					  constp, volatilep, &physname);
 | 
						||
	      if (type == DEBUG_TYPE_NULL)
 | 
						||
		return false;
 | 
						||
	    }
 | 
						||
 | 
						||
	  if (cvars + 1 >= allocvars)
 | 
						||
	    {
 | 
						||
	      allocvars += 10;
 | 
						||
	      variants = ((debug_method_variant *)
 | 
						||
			  xrealloc ((PTR) 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)
 | 
						||
	    return false;
 | 
						||
 | 
						||
	  ++cvars;
 | 
						||
	}
 | 
						||
      while (**pp != ';' && **pp != '\0');
 | 
						||
 | 
						||
      variants[cvars] = DEBUG_METHOD_VARIANT_NULL;
 | 
						||
 | 
						||
      if (**pp != '\0')
 | 
						||
	++*pp;
 | 
						||
 | 
						||
      if (c + 1 >= alloc)
 | 
						||
	{
 | 
						||
	  alloc += 10;
 | 
						||
	  methods = ((debug_method *)
 | 
						||
		     xrealloc ((PTR) methods, alloc * sizeof *methods));
 | 
						||
	}
 | 
						||
 | 
						||
      methods[c] = debug_make_method (dhandle, name, variants);
 | 
						||
 | 
						||
      ++c;
 | 
						||
    }
 | 
						||
 | 
						||
  if (methods != NULL)
 | 
						||
    methods[c] = DEBUG_METHOD_NULL;
 | 
						||
 | 
						||
  *retp = methods;
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Parse a string representing argument types for a method.  Stabs
 | 
						||
   tries to save space by packing argument types into a mangled
 | 
						||
   string.  This string should give us enough information to extract
 | 
						||
   both argument types and the physical name of the function, given
 | 
						||
   the tag name.  */
 | 
						||
 | 
						||
static debug_type
 | 
						||
parse_stab_argtypes (dhandle, info, class_type, fieldname, tagname,
 | 
						||
		     return_type, argtypes, constp, volatilep, pphysname)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     debug_type class_type;
 | 
						||
     const char *fieldname;
 | 
						||
     const char *tagname;
 | 
						||
     debug_type return_type;
 | 
						||
     const char *argtypes;
 | 
						||
     boolean constp;
 | 
						||
     boolean volatilep;
 | 
						||
     const char **pphysname;
 | 
						||
{
 | 
						||
  boolean is_full_physname_constructor;
 | 
						||
  boolean is_constructor;
 | 
						||
  boolean is_destructor;
 | 
						||
  debug_type *args;
 | 
						||
  boolean varargs;
 | 
						||
 | 
						||
  /* Constructors are sometimes handled specially.  */
 | 
						||
  is_full_physname_constructor = ((argtypes[0] == '_'
 | 
						||
				   && argtypes[1] == '_'
 | 
						||
				   && (isdigit ((unsigned char) argtypes[2])
 | 
						||
				       || argtypes[2] == 'Q'
 | 
						||
				       || argtypes[2] == 't'))
 | 
						||
				  || strncmp (argtypes, "__ct", 4) == 0);
 | 
						||
 | 
						||
  is_constructor = (is_full_physname_constructor
 | 
						||
		    || (tagname != NULL
 | 
						||
			&& strcmp (fieldname, tagname) == 0));
 | 
						||
  is_destructor = ((argtypes[0] == '_'
 | 
						||
		    && (argtypes[1] == '$' || argtypes[1] == '.')
 | 
						||
		    && argtypes[2] == '_')
 | 
						||
		   || strncmp (argtypes, "__dt", 4) == 0);
 | 
						||
 | 
						||
  if (is_destructor || is_full_physname_constructor)
 | 
						||
    *pphysname = argtypes;
 | 
						||
  else
 | 
						||
    {
 | 
						||
      unsigned int len;
 | 
						||
      const char *const_prefix;
 | 
						||
      const char *volatile_prefix;
 | 
						||
      char buf[20];
 | 
						||
      unsigned int mangled_name_len;
 | 
						||
      char *physname;
 | 
						||
 | 
						||
      len = tagname == NULL ? 0 : strlen (tagname);
 | 
						||
      const_prefix = constp ? "C" : "";
 | 
						||
      volatile_prefix = volatilep ? "V" : "";
 | 
						||
 | 
						||
      if (len == 0)
 | 
						||
	sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
 | 
						||
      else if (tagname != NULL && strchr (tagname, '<') != NULL)
 | 
						||
	{
 | 
						||
	  /* Template methods are fully mangled.  */
 | 
						||
	  sprintf (buf, "__%s%s", const_prefix, volatile_prefix);
 | 
						||
	  tagname = NULL;
 | 
						||
	  len = 0;
 | 
						||
	}
 | 
						||
      else
 | 
						||
	sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len);
 | 
						||
 | 
						||
      mangled_name_len = ((is_constructor ? 0 : strlen (fieldname))
 | 
						||
			  + strlen (buf)
 | 
						||
			  + len
 | 
						||
			  + strlen (argtypes)
 | 
						||
			  + 1);
 | 
						||
 | 
						||
      if (fieldname[0] == 'o'
 | 
						||
	  && fieldname[1] == 'p'
 | 
						||
	  && (fieldname[2] == '$' || fieldname[2] == '.'))
 | 
						||
	{
 | 
						||
	  const char *opname;
 | 
						||
 | 
						||
	  opname = cplus_mangle_opname (fieldname + 3, 0);
 | 
						||
	  if (opname == NULL)
 | 
						||
	    {
 | 
						||
	      fprintf (stderr, "No mangling for \"%s\"\n", fieldname);
 | 
						||
	      return DEBUG_TYPE_NULL;
 | 
						||
	    }
 | 
						||
	  mangled_name_len += strlen (opname);
 | 
						||
	  physname = (char *) xmalloc (mangled_name_len);
 | 
						||
	  strncpy (physname, fieldname, 3);
 | 
						||
	  strcpy (physname + 3, opname);
 | 
						||
	}
 | 
						||
      else
 | 
						||
	{
 | 
						||
	  physname = (char *) xmalloc (mangled_name_len);
 | 
						||
	  if (is_constructor)
 | 
						||
	    physname[0] = '\0';
 | 
						||
	  else
 | 
						||
	    strcpy (physname, fieldname);
 | 
						||
	}
 | 
						||
 | 
						||
      strcat (physname, buf);
 | 
						||
      if (tagname != NULL)
 | 
						||
	strcat (physname, tagname);
 | 
						||
      strcat (physname, argtypes);
 | 
						||
 | 
						||
      *pphysname = physname;
 | 
						||
    }
 | 
						||
 | 
						||
  if (*argtypes == '\0' || is_destructor)
 | 
						||
    {
 | 
						||
      args = (debug_type *) xmalloc (sizeof *args);
 | 
						||
      *args = NULL;
 | 
						||
      return debug_make_method_type (dhandle, return_type, class_type, args,
 | 
						||
				     false);
 | 
						||
    }
 | 
						||
 | 
						||
  args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs);
 | 
						||
  if (args == NULL)
 | 
						||
    return DEBUG_TYPE_NULL;
 | 
						||
 | 
						||
  return debug_make_method_type (dhandle, return_type, class_type, args,
 | 
						||
				 varargs);
 | 
						||
}
 | 
						||
 | 
						||
/* The tail end of stabs for C++ classes that contain a virtual function
 | 
						||
   pointer contains a tilde, a %, and a type number.
 | 
						||
   The type number refers to the base class (possibly this class itself) which
 | 
						||
   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 boolean
 | 
						||
parse_stab_tilde_field (dhandle, info, pp, typenums, retvptrbase, retownvptr)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char **pp;
 | 
						||
     const int *typenums;
 | 
						||
     debug_type *retvptrbase;
 | 
						||
     boolean *retownvptr;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  const char *hold;
 | 
						||
  int vtypenums[2];
 | 
						||
 | 
						||
  *retvptrbase = DEBUG_TYPE_NULL;
 | 
						||
  *retownvptr = false;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  /* 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))
 | 
						||
    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);
 | 
						||
      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 (dhandle, info, pp, stringp)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char **pp;
 | 
						||
     boolean stringp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  const char *p;
 | 
						||
  int typenums[2];
 | 
						||
  debug_type index_type;
 | 
						||
  boolean 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;
 | 
						||
 | 
						||
  /* FIXME: gdb checks os9k_stabs here.  */
 | 
						||
 | 
						||
  /* If the index type is type 0, we take it as int.  */
 | 
						||
  p = *pp;
 | 
						||
  if (! parse_stab_type_number (&p, typenums))
 | 
						||
    return 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);
 | 
						||
    }
 | 
						||
 | 
						||
  if (**pp != ';')
 | 
						||
    {
 | 
						||
      bad_stab (orig);
 | 
						||
      return DEBUG_TYPE_NULL;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  adjustable = false;
 | 
						||
 | 
						||
  if (! isdigit ((unsigned char) **pp) && **pp != '-')
 | 
						||
    {
 | 
						||
      ++*pp;
 | 
						||
      adjustable = true;
 | 
						||
    }
 | 
						||
 | 
						||
  lower = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
 | 
						||
  if (**pp != ';')
 | 
						||
    {
 | 
						||
      bad_stab (orig);
 | 
						||
      return DEBUG_TYPE_NULL;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  if (! isdigit ((unsigned char) **pp) && **pp != '-')
 | 
						||
    {
 | 
						||
      ++*pp;
 | 
						||
      adjustable = true;
 | 
						||
    }
 | 
						||
 | 
						||
  upper = (bfd_signed_vma) parse_number (pp, (boolean *) NULL);
 | 
						||
  if (**pp != ';')
 | 
						||
    {
 | 
						||
      bad_stab (orig);
 | 
						||
      return DEBUG_TYPE_NULL;
 | 
						||
    }
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp,
 | 
						||
				  (debug_type **) NULL);
 | 
						||
  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 (info, name, hash)
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char *name;
 | 
						||
     bfd_vma hash;
 | 
						||
{
 | 
						||
  struct bincl_file *n;
 | 
						||
 | 
						||
  n = (struct bincl_file *) xmalloc (sizeof *n);
 | 
						||
  n->next = info->bincl_list;
 | 
						||
  n->next_stack = info->bincl_stack;
 | 
						||
  n->name = name;
 | 
						||
  n->hash = hash;
 | 
						||
  n->file = info->files;
 | 
						||
  n->file_types = NULL;
 | 
						||
  info->bincl_list = n;
 | 
						||
  info->bincl_stack = n;
 | 
						||
 | 
						||
  ++info->files;
 | 
						||
  info->file_types = ((struct stab_types **)
 | 
						||
		      xrealloc ((PTR) info->file_types,
 | 
						||
				(info->files
 | 
						||
				 * sizeof *info->file_types)));
 | 
						||
  info->file_types[n->file] = NULL;
 | 
						||
}
 | 
						||
 | 
						||
/* Finish an N_BINCL file, at an N_EINCL, popping the name off the
 | 
						||
   stack.  */
 | 
						||
 | 
						||
static const char *
 | 
						||
pop_bincl (info)
 | 
						||
     struct stab_handle *info;
 | 
						||
{
 | 
						||
  struct bincl_file *o;
 | 
						||
 | 
						||
  o = info->bincl_stack;
 | 
						||
  if (o == NULL)
 | 
						||
    return info->main_filename;
 | 
						||
  info->bincl_stack = o->next_stack;
 | 
						||
 | 
						||
  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 boolean
 | 
						||
find_excl (info, name, hash)
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char *name;
 | 
						||
     bfd_vma hash;
 | 
						||
{
 | 
						||
  struct bincl_file *l;
 | 
						||
 | 
						||
  ++info->files;
 | 
						||
  info->file_types = ((struct stab_types **)
 | 
						||
		      xrealloc ((PTR) info->file_types,
 | 
						||
				(info->files
 | 
						||
				 * sizeof *info->file_types)));
 | 
						||
 | 
						||
  for (l = info->bincl_list; l != NULL; l = l->next)
 | 
						||
    if (l->hash == hash && strcmp (l->name, name) == 0)
 | 
						||
      break;
 | 
						||
  if (l == NULL)
 | 
						||
    {
 | 
						||
      warn_stab (name, "Undefined N_EXCL");
 | 
						||
      info->file_types[info->files - 1] = NULL;
 | 
						||
      return true;
 | 
						||
    }
 | 
						||
 | 
						||
  info->file_types[info->files - 1] = l->file_types;
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Handle a variable definition.  gcc emits variable definitions for a
 | 
						||
   block before the N_LBRAC, so we must hold onto them until we see
 | 
						||
   it.  The SunPRO compiler emits variable definitions after the
 | 
						||
   N_LBRAC, so we can call debug_record_variable immediately.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_record_variable (dhandle, info, name, type, kind, val)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char *name;
 | 
						||
     debug_type type;
 | 
						||
     enum debug_var_kind kind;
 | 
						||
     bfd_vma val;
 | 
						||
{
 | 
						||
  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 = (struct stab_pending_var *) xmalloc (sizeof *v);
 | 
						||
  memset (v, 0, 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 boolean
 | 
						||
stab_emit_pending_vars (dhandle, info)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
{
 | 
						||
  struct stab_pending_var *v;
 | 
						||
 | 
						||
  v = info->pending;
 | 
						||
  while (v != NULL)
 | 
						||
    {
 | 
						||
      struct stab_pending_var *next;
 | 
						||
 | 
						||
      if (! debug_record_variable (dhandle, v->name, v->type, v->kind, v->val))
 | 
						||
	return false;
 | 
						||
 | 
						||
      next = v->next;
 | 
						||
      free (v);
 | 
						||
      v = next;
 | 
						||
    }
 | 
						||
 | 
						||
  info->pending = NULL;
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Find the slot for a type in the database.  */
 | 
						||
 | 
						||
static debug_type *
 | 
						||
stab_find_slot (info, typenums)
 | 
						||
     struct stab_handle *info;
 | 
						||
     const int *typenums;
 | 
						||
{
 | 
						||
  int filenum;
 | 
						||
  int index;
 | 
						||
  struct stab_types **ps;
 | 
						||
 | 
						||
  filenum = typenums[0];
 | 
						||
  index = typenums[1];
 | 
						||
 | 
						||
  if (filenum < 0 || (unsigned int) filenum >= info->files)
 | 
						||
    {
 | 
						||
      fprintf (stderr, "Type file number %d out of range\n", filenum);
 | 
						||
      return NULL;
 | 
						||
    }
 | 
						||
  if (index < 0)
 | 
						||
    {
 | 
						||
      fprintf (stderr, "Type index number %d out of range\n", index);
 | 
						||
      return NULL;
 | 
						||
    }
 | 
						||
 | 
						||
  ps = info->file_types + filenum;
 | 
						||
 | 
						||
  while (index >= STAB_TYPES_SLOTS)
 | 
						||
    {
 | 
						||
      if (*ps == NULL)
 | 
						||
	{
 | 
						||
	  *ps = (struct stab_types *) xmalloc (sizeof **ps);
 | 
						||
	  memset (*ps, 0, sizeof **ps);
 | 
						||
	}
 | 
						||
      ps = &(*ps)->next;
 | 
						||
      index -= STAB_TYPES_SLOTS;
 | 
						||
    }
 | 
						||
  if (*ps == NULL)
 | 
						||
    {
 | 
						||
      *ps = (struct stab_types *) xmalloc (sizeof **ps);
 | 
						||
      memset (*ps, 0, sizeof **ps);
 | 
						||
    }
 | 
						||
 | 
						||
  return (*ps)->types + index;
 | 
						||
}
 | 
						||
 | 
						||
/* Find a type given a type number.  If the type has not been
 | 
						||
   allocated yet, create an indirect type.  */
 | 
						||
 | 
						||
static debug_type
 | 
						||
stab_find_type (dhandle, info, typenums)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const int *typenums;
 | 
						||
{
 | 
						||
  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 (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 boolean
 | 
						||
stab_record_type (dhandle, info, typenums, type)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const int *typenums;
 | 
						||
     debug_type type;
 | 
						||
{
 | 
						||
  debug_type *slot;
 | 
						||
 | 
						||
  slot = stab_find_slot (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 (dhandle, info, typenum)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     int typenum;
 | 
						||
{
 | 
						||
  debug_type rettype;
 | 
						||
  const char *name;
 | 
						||
 | 
						||
  if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT)
 | 
						||
    {
 | 
						||
      fprintf (stderr, "Unrecognized XCOFF type %d\n", typenum);
 | 
						||
      return DEBUG_TYPE_NULL;
 | 
						||
    }
 | 
						||
  if (info->xcoff_types[-typenum] != NULL)
 | 
						||
    return info->xcoff_types[-typenum];
 | 
						||
 | 
						||
  switch (-typenum)
 | 
						||
    {
 | 
						||
    case 1:
 | 
						||
      /* The size of this and all the other types are fixed, defined
 | 
						||
	 by the debugging format.  */
 | 
						||
      name = "int";
 | 
						||
      rettype = debug_make_int_type (dhandle, 4, false);
 | 
						||
      break;
 | 
						||
    case 2:
 | 
						||
      name = "char";
 | 
						||
      rettype = debug_make_int_type (dhandle, 1, false);
 | 
						||
      break;
 | 
						||
    case 3:
 | 
						||
      name = "short";
 | 
						||
      rettype = debug_make_int_type (dhandle, 2, false);
 | 
						||
      break;
 | 
						||
    case 4:
 | 
						||
      name = "long";
 | 
						||
      rettype = debug_make_int_type (dhandle, 4, false);
 | 
						||
      break;
 | 
						||
    case 5:
 | 
						||
      name = "unsigned char";
 | 
						||
      rettype = debug_make_int_type (dhandle, 1, true);
 | 
						||
      break;
 | 
						||
    case 6:
 | 
						||
      name = "signed char";
 | 
						||
      rettype = debug_make_int_type (dhandle, 1, false);
 | 
						||
      break;
 | 
						||
    case 7:
 | 
						||
      name = "unsigned short";
 | 
						||
      rettype = debug_make_int_type (dhandle, 2, true);
 | 
						||
      break;
 | 
						||
    case 8:
 | 
						||
      name = "unsigned int";
 | 
						||
      rettype = debug_make_int_type (dhandle, 4, true);
 | 
						||
      break;
 | 
						||
    case 9:
 | 
						||
      name = "unsigned";
 | 
						||
      rettype = debug_make_int_type (dhandle, 4, true);
 | 
						||
    case 10:
 | 
						||
      name = "unsigned long";
 | 
						||
      rettype = debug_make_int_type (dhandle, 4, true);
 | 
						||
      break;
 | 
						||
    case 11:
 | 
						||
      name = "void";
 | 
						||
      rettype = debug_make_void_type (dhandle);
 | 
						||
      break;
 | 
						||
    case 12:
 | 
						||
      /* IEEE single precision (32 bit).  */
 | 
						||
      name = "float";
 | 
						||
      rettype = debug_make_float_type (dhandle, 4);
 | 
						||
      break;
 | 
						||
    case 13:
 | 
						||
      /* IEEE double precision (64 bit).  */
 | 
						||
      name = "double";
 | 
						||
      rettype = debug_make_float_type (dhandle, 8);
 | 
						||
      break;
 | 
						||
    case 14:
 | 
						||
      /* This is an IEEE double on the RS/6000, and different machines
 | 
						||
	 with different sizes for "long double" should use different
 | 
						||
	 negative type numbers.  See stabs.texinfo.  */
 | 
						||
      name = "long double";
 | 
						||
      rettype = debug_make_float_type (dhandle, 8);
 | 
						||
      break;
 | 
						||
    case 15:
 | 
						||
      name = "integer";
 | 
						||
      rettype = debug_make_int_type (dhandle, 4, false);
 | 
						||
      break;
 | 
						||
    case 16:
 | 
						||
      name = "boolean";
 | 
						||
      rettype = debug_make_bool_type (dhandle, 4);
 | 
						||
      break;
 | 
						||
    case 17:
 | 
						||
      name = "short real";
 | 
						||
      rettype = debug_make_float_type (dhandle, 4);
 | 
						||
      break;
 | 
						||
    case 18:
 | 
						||
      name = "real";
 | 
						||
      rettype = debug_make_float_type (dhandle, 8);
 | 
						||
      break;
 | 
						||
    case 19:
 | 
						||
      /* FIXME */
 | 
						||
      name = "stringptr";
 | 
						||
      rettype = NULL;
 | 
						||
      break;
 | 
						||
    case 20:
 | 
						||
      /* FIXME */
 | 
						||
      name = "character";
 | 
						||
      rettype = debug_make_int_type (dhandle, 1, true);
 | 
						||
      break;
 | 
						||
    case 21:
 | 
						||
      name = "logical*1";
 | 
						||
      rettype = debug_make_bool_type (dhandle, 1);
 | 
						||
      break;
 | 
						||
    case 22:
 | 
						||
      name = "logical*2";
 | 
						||
      rettype = debug_make_bool_type (dhandle, 2);
 | 
						||
      break;
 | 
						||
    case 23:
 | 
						||
      name = "logical*4";
 | 
						||
      rettype = debug_make_bool_type (dhandle, 4);
 | 
						||
      break;
 | 
						||
    case 24:
 | 
						||
      name = "logical";
 | 
						||
      rettype = debug_make_bool_type (dhandle, 4);
 | 
						||
      break;
 | 
						||
    case 25:
 | 
						||
      /* Complex type consisting of two IEEE single precision values.  */
 | 
						||
      name = "complex";
 | 
						||
      rettype = debug_make_complex_type (dhandle, 8);
 | 
						||
      break;
 | 
						||
    case 26:
 | 
						||
      /* Complex type consisting of two IEEE double precision values.  */
 | 
						||
      name = "double complex";
 | 
						||
      rettype = debug_make_complex_type (dhandle, 16);
 | 
						||
      break;
 | 
						||
    case 27:
 | 
						||
      name = "integer*1";
 | 
						||
      rettype = debug_make_int_type (dhandle, 1, false);
 | 
						||
      break;
 | 
						||
    case 28:
 | 
						||
      name = "integer*2";
 | 
						||
      rettype = debug_make_int_type (dhandle, 2, false);
 | 
						||
      break;
 | 
						||
    case 29:
 | 
						||
      name = "integer*4";
 | 
						||
      rettype = debug_make_int_type (dhandle, 4, false);
 | 
						||
      break;
 | 
						||
    case 30:
 | 
						||
      /* FIXME */
 | 
						||
      name = "wchar";
 | 
						||
      rettype = debug_make_int_type (dhandle, 2, false);
 | 
						||
      break;
 | 
						||
    case 31:
 | 
						||
      name = "long long";
 | 
						||
      rettype = debug_make_int_type (dhandle, 8, false);
 | 
						||
      break;
 | 
						||
    case 32:
 | 
						||
      name = "unsigned long long";
 | 
						||
      rettype = debug_make_int_type (dhandle, 8, true);
 | 
						||
      break;
 | 
						||
    case 33:
 | 
						||
      name = "logical*8";
 | 
						||
      rettype = debug_make_bool_type (dhandle, 8);
 | 
						||
      break;
 | 
						||
    case 34:
 | 
						||
      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 (dhandle, info, p, len, kind)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char *p;
 | 
						||
     int len;
 | 
						||
     enum debug_type_kind kind;
 | 
						||
{
 | 
						||
  char *name;
 | 
						||
  debug_type dtype;
 | 
						||
  struct stab_tag *st;
 | 
						||
 | 
						||
  name = savestring (p, len);
 | 
						||
 | 
						||
  /* We pass DEBUG_KIND_ILLEGAL because we want all tags in the same
 | 
						||
     namespace.  This is right for C, and I don't know how to handle
 | 
						||
     other languages.  FIXME.  */
 | 
						||
  dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL);
 | 
						||
  if (dtype != DEBUG_TYPE_NULL)
 | 
						||
    {
 | 
						||
      free (name);
 | 
						||
      return dtype;
 | 
						||
    }
 | 
						||
 | 
						||
  /* We need to allocate an entry on the undefined tag list.  */
 | 
						||
  for (st = info->tags; st != NULL; st = st->next)
 | 
						||
    {
 | 
						||
      if (st->name[0] == name[0]
 | 
						||
	  && strcmp (st->name, name) == 0)
 | 
						||
	{
 | 
						||
	  if (st->kind == DEBUG_KIND_ILLEGAL)
 | 
						||
	    st->kind = kind;
 | 
						||
	  free (name);
 | 
						||
	  break;
 | 
						||
	}
 | 
						||
    }
 | 
						||
  if (st == NULL)
 | 
						||
    {
 | 
						||
      st = (struct stab_tag *) xmalloc (sizeof *st);
 | 
						||
      memset (st, 0, sizeof *st);
 | 
						||
 | 
						||
      st->next = info->tags;
 | 
						||
      st->name = name;
 | 
						||
      st->kind = kind;
 | 
						||
      st->slot = DEBUG_TYPE_NULL;
 | 
						||
      st->type = debug_make_indirect_type (dhandle, &st->slot, name);
 | 
						||
      info->tags = st;
 | 
						||
    }
 | 
						||
 | 
						||
  return st->type;
 | 
						||
}
 | 
						||
 | 
						||
/* In order to get the correct argument types for a stubbed method, we
 | 
						||
   need to extract the argument types from a C++ mangled string.
 | 
						||
   Since the argument types can refer back to the return type, this
 | 
						||
   means that we must demangle the entire physical name.  In gdb this
 | 
						||
   is done by calling cplus_demangle and running the results back
 | 
						||
   through the C++ expression parser.  Since we have no expression
 | 
						||
   parser, we must duplicate much of the work of cplus_demangle here.
 | 
						||
 | 
						||
   We assume that GNU style demangling is used, since this is only
 | 
						||
   done for method stubs, and only g++ should output that form of
 | 
						||
   debugging information.  */
 | 
						||
 | 
						||
/* This structure is used to hold a pointer to type information which
 | 
						||
   demangling a string.  */
 | 
						||
 | 
						||
struct stab_demangle_typestring
 | 
						||
{
 | 
						||
  /* The start of the type.  This is not null terminated.  */
 | 
						||
  const char *typestring;
 | 
						||
  /* The length of the type.  */
 | 
						||
  unsigned int len;
 | 
						||
};
 | 
						||
 | 
						||
/* This structure is used to hold information while demangling a
 | 
						||
   string.  */
 | 
						||
 | 
						||
struct stab_demangle_info
 | 
						||
{
 | 
						||
  /* The debugging information handle.  */
 | 
						||
  PTR dhandle;
 | 
						||
  /* The stab information handle.  */
 | 
						||
  struct stab_handle *info;
 | 
						||
  /* The array of arguments we are building.  */
 | 
						||
  debug_type *args;
 | 
						||
  /* Whether the method takes a variable number of arguments.  */
 | 
						||
  boolean varargs;
 | 
						||
  /* The array of types we have remembered.  */
 | 
						||
  struct stab_demangle_typestring *typestrings;
 | 
						||
  /* The number of typestrings.  */
 | 
						||
  unsigned int typestring_count;
 | 
						||
  /* The number of typestring slots we have allocated.  */
 | 
						||
  unsigned int typestring_alloc;
 | 
						||
};
 | 
						||
 | 
						||
static void stab_bad_demangle PARAMS ((const char *));
 | 
						||
static unsigned int stab_demangle_count PARAMS ((const char **));
 | 
						||
static boolean stab_demangle_get_count
 | 
						||
  PARAMS ((const char **, unsigned int *));
 | 
						||
static boolean stab_demangle_prefix
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char **));
 | 
						||
static boolean stab_demangle_function_name
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char **, const char *));
 | 
						||
static boolean stab_demangle_signature
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char **));
 | 
						||
static boolean stab_demangle_qualified
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
 | 
						||
static boolean stab_demangle_template
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char **));
 | 
						||
static boolean stab_demangle_class
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char **, const char **));
 | 
						||
static boolean stab_demangle_args
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char **, debug_type **,
 | 
						||
	   boolean *));
 | 
						||
static boolean stab_demangle_arg
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char **, debug_type **,
 | 
						||
	   unsigned int *, unsigned int *));
 | 
						||
static boolean stab_demangle_type
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
 | 
						||
static boolean stab_demangle_fund_type
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char **, debug_type *));
 | 
						||
static boolean stab_demangle_remember_type
 | 
						||
  PARAMS ((struct stab_demangle_info *, const char *, int));
 | 
						||
 | 
						||
/* Warn about a bad demangling.  */
 | 
						||
 | 
						||
static void
 | 
						||
stab_bad_demangle (s)
 | 
						||
     const char *s;
 | 
						||
{
 | 
						||
  fprintf (stderr, "bad mangled name `%s'\n", s);
 | 
						||
}
 | 
						||
 | 
						||
/* Get a count from a stab string.  */
 | 
						||
 | 
						||
static unsigned int
 | 
						||
stab_demangle_count (pp)
 | 
						||
     const char **pp;
 | 
						||
{
 | 
						||
  unsigned int count;
 | 
						||
 | 
						||
  count = 0;
 | 
						||
  while (isdigit ((unsigned char) **pp))
 | 
						||
    {
 | 
						||
      count *= 10;
 | 
						||
      count += **pp - '0';
 | 
						||
      ++*pp;
 | 
						||
    }
 | 
						||
  return count;
 | 
						||
}
 | 
						||
 | 
						||
/* Require a count in a string.  The count may be multiple digits, in
 | 
						||
   which case it must end in an underscore.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_get_count (pp, pi)
 | 
						||
     const char **pp;
 | 
						||
     unsigned int *pi;
 | 
						||
{
 | 
						||
  if (! isdigit ((unsigned char) **pp))
 | 
						||
    return false;
 | 
						||
 | 
						||
  *pi = **pp - '0';
 | 
						||
  ++*pp;
 | 
						||
  if (isdigit ((unsigned char) **pp))
 | 
						||
    {
 | 
						||
      unsigned int count;
 | 
						||
      const char *p;
 | 
						||
 | 
						||
      count = *pi;
 | 
						||
      p = *pp;
 | 
						||
      do
 | 
						||
	{
 | 
						||
	  count *= 10;
 | 
						||
	  count += *p - '0';
 | 
						||
	  ++p;
 | 
						||
	}
 | 
						||
      while (isdigit ((unsigned char) *p));
 | 
						||
      if (*p == '_')
 | 
						||
	{
 | 
						||
	  *pp = p + 1;
 | 
						||
	  *pi = count;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* This function demangles a physical name, returning a NULL
 | 
						||
   terminated array of argument types.  */
 | 
						||
 | 
						||
static debug_type *
 | 
						||
stab_demangle_argtypes (dhandle, info, physname, pvarargs)
 | 
						||
     PTR dhandle;
 | 
						||
     struct stab_handle *info;
 | 
						||
     const char *physname;
 | 
						||
     boolean *pvarargs;
 | 
						||
{
 | 
						||
  struct stab_demangle_info minfo;
 | 
						||
 | 
						||
  minfo.dhandle = dhandle;
 | 
						||
  minfo.info = info;
 | 
						||
  minfo.args = NULL;
 | 
						||
  minfo.varargs = false;
 | 
						||
  minfo.typestring_alloc = 10;
 | 
						||
  minfo.typestrings = ((struct stab_demangle_typestring *)
 | 
						||
		       xmalloc (minfo.typestring_alloc
 | 
						||
				* sizeof *minfo.typestrings));
 | 
						||
  minfo.typestring_count = 0;
 | 
						||
 | 
						||
  /* cplus_demangle checks for special GNU mangled forms, but we can't
 | 
						||
     see any of them in mangled method argument types.  */
 | 
						||
 | 
						||
  if (! stab_demangle_prefix (&minfo, &physname))
 | 
						||
    goto error_return;
 | 
						||
 | 
						||
  if (*physname != '\0')
 | 
						||
    {
 | 
						||
      if (! stab_demangle_signature (&minfo, &physname))
 | 
						||
	goto error_return;
 | 
						||
    }
 | 
						||
 | 
						||
  free (minfo.typestrings);
 | 
						||
  minfo.typestrings = NULL;
 | 
						||
 | 
						||
  if (minfo.args == NULL)
 | 
						||
    fprintf (stderr, "no argument types in mangled string\n");
 | 
						||
 | 
						||
  *pvarargs = minfo.varargs;
 | 
						||
  return minfo.args;
 | 
						||
 | 
						||
 error_return:
 | 
						||
  if (minfo.typestrings != NULL)
 | 
						||
    free (minfo.typestrings);
 | 
						||
  return NULL;
 | 
						||
}
 | 
						||
 | 
						||
/* Demangle the prefix of the mangled name.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_prefix (minfo, pp)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char **pp;
 | 
						||
{
 | 
						||
  const char *scan;
 | 
						||
  unsigned int i;
 | 
						||
 | 
						||
  /* cplus_demangle checks for global constructors and destructors,
 | 
						||
     but we can't see them in mangled argument types.  */
 | 
						||
 | 
						||
  /* Look for `__'.  */
 | 
						||
  scan = *pp;
 | 
						||
  do
 | 
						||
    {
 | 
						||
      scan = strchr (scan, '_');
 | 
						||
    }
 | 
						||
  while (scan != NULL && *++scan != '_');
 | 
						||
 | 
						||
  if (scan == NULL)
 | 
						||
    {
 | 
						||
      stab_bad_demangle (*pp);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
 | 
						||
  --scan;
 | 
						||
 | 
						||
  /* We found `__'; move ahead to the last contiguous `__' pair.  */
 | 
						||
  i = strspn (scan, "_");
 | 
						||
  if (i > 2)
 | 
						||
    scan += i - 2;
 | 
						||
 | 
						||
  if (scan == *pp
 | 
						||
      && (isdigit ((unsigned char) scan[2])
 | 
						||
	  || scan[2] == 'Q'
 | 
						||
	  || scan[2] == 't'))
 | 
						||
    {
 | 
						||
      /* This is a GNU style constructor name.  */
 | 
						||
      *pp = scan + 2;
 | 
						||
      return true;
 | 
						||
    }
 | 
						||
  else if (scan == *pp
 | 
						||
	   && ! isdigit ((unsigned char) scan[2])
 | 
						||
	   && scan[2] != 't')
 | 
						||
    {
 | 
						||
      /* Look for the `__' that separates the prefix from the
 | 
						||
         signature.  */
 | 
						||
      while (*scan == '_')
 | 
						||
	++scan;
 | 
						||
      scan = strstr (scan, "__");
 | 
						||
      if (scan == NULL || scan[2] == '\0')
 | 
						||
	{
 | 
						||
	  stab_bad_demangle (*pp);
 | 
						||
	  return false;
 | 
						||
	}
 | 
						||
 | 
						||
      return stab_demangle_function_name (minfo, pp, scan);
 | 
						||
    }
 | 
						||
  else if (scan[2] != '\0')
 | 
						||
    {
 | 
						||
      /* The name doesn't start with `__', but it does contain `__'.  */
 | 
						||
      return stab_demangle_function_name (minfo, pp, scan);
 | 
						||
    }
 | 
						||
  else
 | 
						||
    {
 | 
						||
      stab_bad_demangle (*pp);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
  /*NOTREACHED*/
 | 
						||
}
 | 
						||
 | 
						||
/* Demangle a function name prefix.  The scan argument points to the
 | 
						||
   double underscore which separates the function name from the
 | 
						||
   signature.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_function_name (minfo, pp, scan)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char **pp;
 | 
						||
     const char *scan;
 | 
						||
{
 | 
						||
  const char *name;
 | 
						||
 | 
						||
  /* The string from *pp to scan is the name of the function.  We
 | 
						||
     don't care about the name, since we just looking for argument
 | 
						||
     types.  However, for conversion operators, the name may include a
 | 
						||
     type which we must remember in order to handle backreferences.  */
 | 
						||
 | 
						||
  name = *pp;
 | 
						||
  *pp = scan + 2;
 | 
						||
 | 
						||
  if (*pp - name >= 5
 | 
						||
	   && strncmp (name, "type", 4) == 0
 | 
						||
	   && (name[4] == '$' || name[4] == '.'))
 | 
						||
    {
 | 
						||
      const char *tem;
 | 
						||
 | 
						||
      /* This is a type conversion operator.  */
 | 
						||
      tem = name + 5;
 | 
						||
      if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
 | 
						||
	return false;
 | 
						||
    }
 | 
						||
  else if (name[0] == '_'
 | 
						||
	   && name[1] == '_'
 | 
						||
	   && name[2] == 'o'
 | 
						||
	   && name[3] == 'p')
 | 
						||
    {
 | 
						||
      const char *tem;
 | 
						||
 | 
						||
      /* This is a type conversion operator.  */
 | 
						||
      tem = name + 4;
 | 
						||
      if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL))
 | 
						||
	return false;
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Demangle the signature.  This is where the argument types are
 | 
						||
   found.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_signature (minfo, pp)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char **pp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  boolean expect_func, func_done;
 | 
						||
  const char *hold;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  expect_func = false;
 | 
						||
  func_done = false;
 | 
						||
  hold = NULL;
 | 
						||
 | 
						||
  while (**pp != '\0')
 | 
						||
    {
 | 
						||
      switch (**pp)
 | 
						||
	{
 | 
						||
	case 'Q':
 | 
						||
	  hold = *pp;
 | 
						||
	  if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL)
 | 
						||
	      || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
 | 
						||
	    return false;
 | 
						||
	  expect_func = true;
 | 
						||
	  hold = NULL;
 | 
						||
	  break;
 | 
						||
 | 
						||
	case 'S':
 | 
						||
	  /* Static member function.  FIXME: Can this happen?  */
 | 
						||
	  if (hold == NULL)
 | 
						||
	    hold = *pp;
 | 
						||
	  ++*pp;
 | 
						||
	  break;
 | 
						||
 | 
						||
	case 'C':
 | 
						||
	  /* Const member function.  */
 | 
						||
	  if (hold == NULL)
 | 
						||
	    hold = *pp;
 | 
						||
	  ++*pp;
 | 
						||
	  break;
 | 
						||
 | 
						||
	case '0': case '1': case '2': case '3': case '4':
 | 
						||
	case '5': case '6': case '7': case '8': case '9':
 | 
						||
	  if (hold == NULL)
 | 
						||
	    hold = *pp;
 | 
						||
	  if (! stab_demangle_class (minfo, pp, (const char **) NULL)
 | 
						||
	      || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
 | 
						||
	    return false;
 | 
						||
	  expect_func = true;
 | 
						||
	  hold = NULL;
 | 
						||
	  break;
 | 
						||
 | 
						||
	case 'F':
 | 
						||
	  /* Function.  I don't know if this actually happens with g++
 | 
						||
             output.  */
 | 
						||
	  hold = NULL;
 | 
						||
	  func_done = true;
 | 
						||
	  ++*pp;
 | 
						||
	  if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
 | 
						||
	    return false;
 | 
						||
	  break;
 | 
						||
 | 
						||
	case 't':
 | 
						||
	  /* Template.  */
 | 
						||
	  if (hold == NULL)
 | 
						||
	    hold = *pp;
 | 
						||
	  if (! stab_demangle_template (minfo, pp)
 | 
						||
	      || ! stab_demangle_remember_type (minfo, hold, *pp - hold))
 | 
						||
	    return false;
 | 
						||
	  hold = NULL;
 | 
						||
	  expect_func = true;
 | 
						||
	  break;
 | 
						||
 | 
						||
	case '_':
 | 
						||
	  /* At the outermost level, we cannot have a return type
 | 
						||
	     specified, so if we run into another '_' at this point we
 | 
						||
	     are dealing with a mangled name that is either bogus, or
 | 
						||
	     has been mangled by some algorithm we don't know how to
 | 
						||
	     deal with.  So just reject the entire demangling.  */
 | 
						||
	  stab_bad_demangle (orig);
 | 
						||
	  return false;
 | 
						||
 | 
						||
	default:
 | 
						||
	  /* Assume we have stumbled onto the first outermost function
 | 
						||
	     argument token, and start processing args.  */
 | 
						||
	  func_done = true;
 | 
						||
	  if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
 | 
						||
	    return false;
 | 
						||
	  break;
 | 
						||
	}
 | 
						||
 | 
						||
      if (expect_func)
 | 
						||
	{
 | 
						||
	  func_done = true;
 | 
						||
	  if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
 | 
						||
	    return false;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  if (! func_done)
 | 
						||
    {
 | 
						||
      /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
 | 
						||
	 bar__3fooi is 'foo::bar(int)'.  We get here when we find the
 | 
						||
	 first case, and need to ensure that the '(void)' gets added
 | 
						||
	 to the current declp.  */
 | 
						||
      if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs))
 | 
						||
	return false;
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Demangle a qualified name, such as "Q25Outer5Inner" which is the
 | 
						||
   mangled form of "Outer::Inner".  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_qualified (minfo, pp, ptype)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char **pp;
 | 
						||
     debug_type *ptype;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  const char *p;
 | 
						||
  unsigned int qualifiers;
 | 
						||
  debug_type context;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  switch ((*pp)[1])
 | 
						||
    {
 | 
						||
    case '_':
 | 
						||
      /* GNU mangled name with more than 9 classes.  The count is
 | 
						||
	 preceded by an underscore (to distinguish it from the <= 9
 | 
						||
	 case) and followed by an underscore.  */
 | 
						||
      p = *pp + 2;
 | 
						||
      if (! isdigit ((unsigned char) *p) || *p == '0')
 | 
						||
	{
 | 
						||
	  stab_bad_demangle (orig);
 | 
						||
	  return false;
 | 
						||
	}
 | 
						||
      qualifiers = atoi (p);
 | 
						||
      while (isdigit ((unsigned char) *p))
 | 
						||
	++p;
 | 
						||
      if (*p != '_')
 | 
						||
	{
 | 
						||
	  stab_bad_demangle (orig);
 | 
						||
	  return false;
 | 
						||
	}
 | 
						||
      *pp = p + 1;
 | 
						||
      break;
 | 
						||
 | 
						||
    case '1': case '2': case '3': case '4': case '5':
 | 
						||
    case '6': case '7': case '8': case '9':
 | 
						||
      qualifiers = (*pp)[1] - '0';
 | 
						||
      /* Skip an optional underscore after the count.  */
 | 
						||
      if ((*pp)[2] == '_')
 | 
						||
	++*pp;
 | 
						||
      *pp += 2;
 | 
						||
      break;
 | 
						||
 | 
						||
    case '0':
 | 
						||
    default:
 | 
						||
      stab_bad_demangle (orig);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
 | 
						||
  context = DEBUG_TYPE_NULL;
 | 
						||
 | 
						||
  /* Pick off the names.  */
 | 
						||
  while (qualifiers-- > 0)
 | 
						||
    {
 | 
						||
      if (**pp == '_')
 | 
						||
	++*pp;
 | 
						||
      if (**pp == 't')
 | 
						||
	{
 | 
						||
	  /* FIXME: I don't know how to handle the ptype != NULL case
 | 
						||
             here.  */
 | 
						||
	  if (! stab_demangle_template (minfo, pp))
 | 
						||
	    return false;
 | 
						||
	}
 | 
						||
      else
 | 
						||
	{
 | 
						||
	  unsigned int len;
 | 
						||
 | 
						||
	  len = stab_demangle_count (pp);
 | 
						||
	  if (strlen (*pp) < len)
 | 
						||
	    {
 | 
						||
	      stab_bad_demangle (orig);
 | 
						||
	      return false;
 | 
						||
	    }
 | 
						||
 | 
						||
	  if (ptype != NULL)
 | 
						||
	    {
 | 
						||
	      const debug_field *fields;
 | 
						||
 | 
						||
	      fields = NULL;
 | 
						||
	      if (context != DEBUG_TYPE_NULL)
 | 
						||
		fields = debug_get_fields (minfo->dhandle, context);
 | 
						||
 | 
						||
	      context = DEBUG_TYPE_NULL;
 | 
						||
 | 
						||
	      if (fields != NULL)
 | 
						||
		{
 | 
						||
		  char *name;
 | 
						||
 | 
						||
		  /* Try to find the type by looking through the
 | 
						||
                     fields of context until we find a field with the
 | 
						||
                     same type.  This ought to work for a class
 | 
						||
                     defined within a class, but it won't work for,
 | 
						||
                     e.g., an enum defined within a class.  stabs does
 | 
						||
                     not give us enough information to figure out the
 | 
						||
                     latter case.  */
 | 
						||
 | 
						||
		  name = savestring (*pp, len);
 | 
						||
 | 
						||
		  for (; *fields != DEBUG_FIELD_NULL; fields++)
 | 
						||
		    {
 | 
						||
		      debug_type ft;
 | 
						||
		      const char *dn;
 | 
						||
 | 
						||
		      ft = debug_get_field_type (minfo->dhandle, *fields);
 | 
						||
		      if (ft == NULL)
 | 
						||
			return false;
 | 
						||
		      dn = debug_get_type_name (minfo->dhandle, ft);
 | 
						||
		      if (dn != NULL && strcmp (dn, name) == 0)
 | 
						||
			{
 | 
						||
			  context = ft;
 | 
						||
			  break;
 | 
						||
			}
 | 
						||
		    }
 | 
						||
 | 
						||
		  free (name);
 | 
						||
		}
 | 
						||
 | 
						||
	      if (context == DEBUG_TYPE_NULL)
 | 
						||
		{
 | 
						||
	  /* We have to fall back on finding the type by name.
 | 
						||
                     If there are more types to come, then this must
 | 
						||
                     be a class.  Otherwise, it could be anything.  */
 | 
						||
 | 
						||
		  if (qualifiers == 0)
 | 
						||
		    {
 | 
						||
		      char *name;
 | 
						||
 | 
						||
		      name = savestring (*pp, len);
 | 
						||
		      context = debug_find_named_type (minfo->dhandle,
 | 
						||
						       name);
 | 
						||
		      free (name);
 | 
						||
		    }
 | 
						||
 | 
						||
		  if (context == DEBUG_TYPE_NULL)
 | 
						||
		    {
 | 
						||
		      context = stab_find_tagged_type (minfo->dhandle,
 | 
						||
						       minfo->info,
 | 
						||
						       *pp, len,
 | 
						||
						       (qualifiers == 0
 | 
						||
							? DEBUG_KIND_ILLEGAL
 | 
						||
							: DEBUG_KIND_CLASS));
 | 
						||
		      if (context == DEBUG_TYPE_NULL)
 | 
						||
			return false;
 | 
						||
		    }
 | 
						||
		}
 | 
						||
	    }
 | 
						||
 | 
						||
	  *pp += len;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  if (ptype != NULL)
 | 
						||
    *ptype = context;
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Demangle a template.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_template (minfo, pp)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char **pp;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  unsigned int r, i;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  ++*pp;
 | 
						||
 | 
						||
  /* Skip the template name.  */
 | 
						||
  r = stab_demangle_count (pp);
 | 
						||
  if (r == 0 || strlen (*pp) < r)
 | 
						||
    {
 | 
						||
      stab_bad_demangle (orig);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
  *pp += r;
 | 
						||
 | 
						||
  /* Get the size of the parameter list.  */
 | 
						||
  if (stab_demangle_get_count (pp, &r) == 0)
 | 
						||
    {
 | 
						||
      stab_bad_demangle (orig);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
 | 
						||
  for (i = 0; i < r; i++)
 | 
						||
    {
 | 
						||
      if (**pp == 'Z')
 | 
						||
	{
 | 
						||
	  /* This is a type parameter.  */
 | 
						||
	  ++*pp;
 | 
						||
	  if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
 | 
						||
	    return false;
 | 
						||
	}
 | 
						||
      else
 | 
						||
	{
 | 
						||
	  const char *old_p;
 | 
						||
	  boolean pointerp, realp, integralp, charp, boolp;
 | 
						||
	  boolean done;
 | 
						||
 | 
						||
	  old_p = *pp;
 | 
						||
	  pointerp = false;
 | 
						||
	  realp = false;
 | 
						||
	  integralp = false;
 | 
						||
	  charp = false;
 | 
						||
	  boolp = false;
 | 
						||
	  done = false;
 | 
						||
 | 
						||
	  /* This is a value parameter.  */
 | 
						||
 | 
						||
	  if (! stab_demangle_type (minfo, pp, (debug_type *) NULL))
 | 
						||
	    return false;
 | 
						||
 | 
						||
	  while (*old_p != '\0' && ! done)
 | 
						||
	    {
 | 
						||
	      switch (*old_p)
 | 
						||
		{
 | 
						||
		case 'P':
 | 
						||
		case 'p':
 | 
						||
		case 'R':
 | 
						||
		  pointerp = true;
 | 
						||
		  done = true;
 | 
						||
		  break;
 | 
						||
		case 'C':	/* Const.  */
 | 
						||
		case 'S':	/* Signed.  */
 | 
						||
		case 'U':	/* Unsigned.  */
 | 
						||
		case 'V':	/* Volatile.  */
 | 
						||
		case 'F':	/* Function.  */
 | 
						||
		case 'M':	/* Member function.  */
 | 
						||
		case 'O':	/* ??? */
 | 
						||
		  ++old_p;
 | 
						||
		  break;
 | 
						||
		case 'Q':	/* Qualified name.  */
 | 
						||
		  integralp = true;
 | 
						||
		  done = true;
 | 
						||
		  break;
 | 
						||
		case 'T':	/* Remembered type.  */
 | 
						||
		  abort ();
 | 
						||
		case 'v':	/* Void.  */
 | 
						||
		  abort ();
 | 
						||
		case 'x':	/* Long long.  */
 | 
						||
		case 'l':	/* Long.  */
 | 
						||
		case 'i':	/* Int.  */
 | 
						||
		case 's':	/* Short.  */
 | 
						||
		case 'w':	/* Wchar_t.  */
 | 
						||
		  integralp = true;
 | 
						||
		  done = true;
 | 
						||
		  break;
 | 
						||
		case 'b':	/* Bool.  */
 | 
						||
		  boolp = true;
 | 
						||
		  done = true;
 | 
						||
		  break;
 | 
						||
		case 'c':	/* Char.  */
 | 
						||
		  charp = true;
 | 
						||
		  done = true;
 | 
						||
		  break;
 | 
						||
		case 'r':	/* Long double.  */
 | 
						||
		case 'd':	/* Double.  */
 | 
						||
		case 'f':	/* Float.  */
 | 
						||
		  realp = true;
 | 
						||
		  done = true;
 | 
						||
		  break;
 | 
						||
		default:
 | 
						||
		  /* Assume it's a user defined integral type.  */
 | 
						||
		  integralp = true;
 | 
						||
		  done = true;
 | 
						||
		  break;
 | 
						||
		}
 | 
						||
	    }
 | 
						||
 | 
						||
	  if (integralp)
 | 
						||
	    {
 | 
						||
	      if (**pp == 'm')
 | 
						||
		++*pp;
 | 
						||
	      while (isdigit ((unsigned char) **pp))
 | 
						||
		++*pp;
 | 
						||
	    }
 | 
						||
	  else if (charp)
 | 
						||
	    {
 | 
						||
	      unsigned int val;
 | 
						||
 | 
						||
	      if (**pp == 'm')
 | 
						||
		++*pp;
 | 
						||
	      val = stab_demangle_count (pp);
 | 
						||
	      if (val == 0)
 | 
						||
		{
 | 
						||
		  stab_bad_demangle (orig);
 | 
						||
		  return false;
 | 
						||
		}
 | 
						||
	    }
 | 
						||
	  else if (boolp)
 | 
						||
	    {
 | 
						||
	      unsigned int val;
 | 
						||
 | 
						||
	      val = stab_demangle_count (pp);
 | 
						||
	      if (val != 0 && val != 1)
 | 
						||
		{
 | 
						||
		  stab_bad_demangle (orig);
 | 
						||
		  return false;
 | 
						||
		}
 | 
						||
	    }
 | 
						||
	  else if (realp)
 | 
						||
	    {
 | 
						||
	      if (**pp == 'm')
 | 
						||
		++*pp;
 | 
						||
	      while (isdigit ((unsigned char) **pp))
 | 
						||
		++*pp;
 | 
						||
	      if (**pp == '.')
 | 
						||
		{
 | 
						||
		  ++*pp;
 | 
						||
		  while (isdigit ((unsigned char) **pp))
 | 
						||
		    ++*pp;
 | 
						||
		}
 | 
						||
	      if (**pp == 'e')
 | 
						||
		{
 | 
						||
		  ++*pp;
 | 
						||
		  while (isdigit ((unsigned char) **pp))
 | 
						||
		    ++*pp;
 | 
						||
		}
 | 
						||
	    }
 | 
						||
	  else if (pointerp)
 | 
						||
	    {
 | 
						||
	      unsigned int len;
 | 
						||
 | 
						||
	      if (! stab_demangle_get_count (pp, &len))
 | 
						||
		{
 | 
						||
		  stab_bad_demangle (orig);
 | 
						||
		  return false;
 | 
						||
		}
 | 
						||
	      *pp += len;
 | 
						||
	    }
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Demangle a class name.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_class (minfo, pp, pstart)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char **pp;
 | 
						||
     const char **pstart;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  unsigned int n;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  n = stab_demangle_count (pp);
 | 
						||
  if (strlen (*pp) < n)
 | 
						||
    {
 | 
						||
      stab_bad_demangle (orig);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
 | 
						||
  if (pstart != NULL)
 | 
						||
    *pstart = *pp;
 | 
						||
 | 
						||
  *pp += n;
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Demangle function arguments.  If the pargs argument is not NULL, it
 | 
						||
   is set to a NULL terminated array holding the arguments.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_args (minfo, pp, pargs, pvarargs)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char **pp;
 | 
						||
     debug_type **pargs;
 | 
						||
     boolean *pvarargs;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  unsigned int alloc, count;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  alloc = 10;
 | 
						||
  if (pargs != NULL)
 | 
						||
    {
 | 
						||
      *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs);
 | 
						||
      *pvarargs = false;
 | 
						||
    }
 | 
						||
  count = 0;
 | 
						||
 | 
						||
  while (**pp != '_' && **pp != '\0' && **pp != 'e')
 | 
						||
    {
 | 
						||
      if (**pp == 'N' || **pp == 'T')
 | 
						||
	{
 | 
						||
	  char temptype;
 | 
						||
	  unsigned int r, t;
 | 
						||
 | 
						||
	  temptype = **pp;
 | 
						||
	  ++*pp;
 | 
						||
 | 
						||
	  if (temptype == 'T')
 | 
						||
	    r = 1;
 | 
						||
	  else
 | 
						||
	    {
 | 
						||
	      if (! stab_demangle_get_count (pp, &r))
 | 
						||
		{
 | 
						||
		  stab_bad_demangle (orig);
 | 
						||
		  return false;
 | 
						||
		}
 | 
						||
	    }
 | 
						||
 | 
						||
	  if (! stab_demangle_get_count (pp, &t))
 | 
						||
	    {
 | 
						||
	      stab_bad_demangle (orig);
 | 
						||
	      return false;
 | 
						||
	    }
 | 
						||
 | 
						||
	  if (t >= minfo->typestring_count)
 | 
						||
	    {
 | 
						||
	      stab_bad_demangle (orig);
 | 
						||
	      return false;
 | 
						||
	    }
 | 
						||
	  while (r-- > 0)
 | 
						||
	    {
 | 
						||
	      const char *tem;
 | 
						||
 | 
						||
	      tem = minfo->typestrings[t].typestring;
 | 
						||
	      if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc))
 | 
						||
		return false;
 | 
						||
	    }
 | 
						||
	}
 | 
						||
      else
 | 
						||
	{
 | 
						||
	  if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc))
 | 
						||
	    return false;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  if (pargs != NULL)
 | 
						||
    (*pargs)[count] = DEBUG_TYPE_NULL;
 | 
						||
 | 
						||
  if (**pp == 'e')
 | 
						||
    {
 | 
						||
      if (pargs != NULL)
 | 
						||
	*pvarargs = true;
 | 
						||
      ++*pp;
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Demangle a single argument.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_arg (minfo, pp, pargs, pcount, palloc)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char **pp;
 | 
						||
     debug_type **pargs;
 | 
						||
     unsigned int *pcount;
 | 
						||
     unsigned int *palloc;
 | 
						||
{
 | 
						||
  const char *start;
 | 
						||
  debug_type type;
 | 
						||
 | 
						||
  start = *pp;
 | 
						||
  if (! stab_demangle_type (minfo, pp,
 | 
						||
			    pargs == NULL ? (debug_type *) NULL : &type)
 | 
						||
      || ! stab_demangle_remember_type (minfo, start, *pp - start))
 | 
						||
    return false;
 | 
						||
 | 
						||
  if (pargs != NULL)
 | 
						||
    {
 | 
						||
      if (type == DEBUG_TYPE_NULL)
 | 
						||
	return false;
 | 
						||
 | 
						||
      if (*pcount + 1 >= *palloc)
 | 
						||
	{
 | 
						||
	  *palloc += 10;
 | 
						||
	  *pargs = ((debug_type *)
 | 
						||
		    xrealloc (*pargs, *palloc * sizeof **pargs));
 | 
						||
	}
 | 
						||
      (*pargs)[*pcount] = type;
 | 
						||
      ++*pcount;
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Demangle a type.  If the ptype argument is not NULL, *ptype is set
 | 
						||
   to the newly allocated type.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_type (minfo, pp, ptype)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char **pp;
 | 
						||
     debug_type *ptype;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  switch (**pp)
 | 
						||
    {
 | 
						||
    case 'P':
 | 
						||
    case 'p':
 | 
						||
      /* A pointer type.  */
 | 
						||
      ++*pp;
 | 
						||
      if (! stab_demangle_type (minfo, pp, ptype))
 | 
						||
	return false;
 | 
						||
      if (ptype != NULL)
 | 
						||
	*ptype = debug_make_pointer_type (minfo->dhandle, *ptype);
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'R':
 | 
						||
      /* A reference type.  */
 | 
						||
      ++*pp;
 | 
						||
      if (! stab_demangle_type (minfo, pp, ptype))
 | 
						||
	return false;
 | 
						||
      if (ptype != NULL)
 | 
						||
	*ptype = debug_make_reference_type (minfo->dhandle, *ptype);
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'A':
 | 
						||
      /* An array.  */
 | 
						||
      {
 | 
						||
	unsigned long high;
 | 
						||
 | 
						||
	++*pp;
 | 
						||
	high = 0;
 | 
						||
	while (**pp != '\0' && **pp != '_')
 | 
						||
	  {
 | 
						||
	    if (! isdigit ((unsigned char) **pp))
 | 
						||
	      {
 | 
						||
		stab_bad_demangle (orig);
 | 
						||
		return false;
 | 
						||
	      }
 | 
						||
	    high *= 10;
 | 
						||
	    high += **pp - '0';
 | 
						||
	    ++*pp;
 | 
						||
	  }
 | 
						||
	if (**pp != '_')
 | 
						||
	  {
 | 
						||
	    stab_bad_demangle (orig);
 | 
						||
	    return false;
 | 
						||
	  }
 | 
						||
	++*pp;
 | 
						||
 | 
						||
	if (! stab_demangle_type (minfo, pp, ptype))
 | 
						||
	  return false;
 | 
						||
	if (ptype != NULL)
 | 
						||
	  {
 | 
						||
	    debug_type int_type;
 | 
						||
 | 
						||
	    int_type = debug_find_named_type (minfo->dhandle, "int");
 | 
						||
	    if (int_type == NULL)
 | 
						||
	      int_type = debug_make_int_type (minfo->dhandle, 4, false);
 | 
						||
	    *ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type,
 | 
						||
					    0, high, false);
 | 
						||
	  }
 | 
						||
      }
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'T':
 | 
						||
      /* A back reference to a remembered type.  */
 | 
						||
      {
 | 
						||
	unsigned int i;
 | 
						||
	const char *p;
 | 
						||
 | 
						||
	++*pp;
 | 
						||
	if (! stab_demangle_get_count (pp, &i))
 | 
						||
	  {
 | 
						||
	    stab_bad_demangle (orig);
 | 
						||
	    return false;
 | 
						||
	  }
 | 
						||
	if (i >= minfo->typestring_count)
 | 
						||
	  {
 | 
						||
	    stab_bad_demangle (orig);
 | 
						||
	    return false;
 | 
						||
	  }
 | 
						||
	p = minfo->typestrings[i].typestring;
 | 
						||
	if (! stab_demangle_type (minfo, &p, ptype))
 | 
						||
	  return false;
 | 
						||
      }
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'F':
 | 
						||
      /* A function.  */
 | 
						||
      {
 | 
						||
	debug_type *args;
 | 
						||
	boolean varargs;
 | 
						||
 | 
						||
	++*pp;
 | 
						||
	if (! stab_demangle_args (minfo, pp,
 | 
						||
				  (ptype == NULL
 | 
						||
				   ? (debug_type **) NULL
 | 
						||
				   : &args),
 | 
						||
				  (ptype == NULL
 | 
						||
				   ? (boolean *) NULL
 | 
						||
				   : &varargs)))
 | 
						||
	  return false;
 | 
						||
	if (**pp != '_')
 | 
						||
	  {
 | 
						||
	    /* cplus_demangle will accept a function without a return
 | 
						||
	       type, but I don't know when that will happen, or what
 | 
						||
	       to do if it does.  */
 | 
						||
	    stab_bad_demangle (orig);
 | 
						||
	    return false;
 | 
						||
	  }
 | 
						||
	++*pp;
 | 
						||
	if (! stab_demangle_type (minfo, pp, ptype))
 | 
						||
	  return false;
 | 
						||
	if (ptype != NULL)
 | 
						||
	  *ptype = debug_make_function_type (minfo->dhandle, *ptype, args,
 | 
						||
					     varargs);
 | 
						||
 | 
						||
      }
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'M':
 | 
						||
    case 'O':
 | 
						||
      {
 | 
						||
	boolean memberp, constp, volatilep;
 | 
						||
	debug_type *args;
 | 
						||
	boolean varargs;
 | 
						||
	unsigned int n;
 | 
						||
	const char *name;
 | 
						||
 | 
						||
	memberp = **pp == 'M';
 | 
						||
	constp = false;
 | 
						||
	volatilep = false;
 | 
						||
	args = NULL;
 | 
						||
	varargs = false;
 | 
						||
 | 
						||
	++*pp;
 | 
						||
	if (! isdigit ((unsigned char) **pp))
 | 
						||
	  {
 | 
						||
	    stab_bad_demangle (orig);
 | 
						||
	    return false;
 | 
						||
	  }
 | 
						||
	n = stab_demangle_count (pp);
 | 
						||
	if (strlen (*pp) < n)
 | 
						||
	  {
 | 
						||
	    stab_bad_demangle (orig);
 | 
						||
	    return false;
 | 
						||
	  }
 | 
						||
	name = *pp;
 | 
						||
	*pp += n;
 | 
						||
 | 
						||
	if (memberp)
 | 
						||
	  {
 | 
						||
	    if (**pp == 'C')
 | 
						||
	      {
 | 
						||
		constp = true;
 | 
						||
		++*pp;
 | 
						||
	      }
 | 
						||
	    else if (**pp == 'V')
 | 
						||
	      {
 | 
						||
		volatilep = true;
 | 
						||
		++*pp;
 | 
						||
	      }
 | 
						||
	    if (**pp != 'F')
 | 
						||
	      {
 | 
						||
		stab_bad_demangle (orig);
 | 
						||
		return false;
 | 
						||
	      }
 | 
						||
	    ++*pp;
 | 
						||
	    if (! stab_demangle_args (minfo, pp,
 | 
						||
				      (ptype == NULL
 | 
						||
				       ? (debug_type **) NULL
 | 
						||
				       : &args),
 | 
						||
				      (ptype == NULL
 | 
						||
				       ? (boolean *) NULL
 | 
						||
				       : &varargs)))
 | 
						||
	      return false;
 | 
						||
	  }
 | 
						||
 | 
						||
	if (**pp != '_')
 | 
						||
	  {
 | 
						||
	    stab_bad_demangle (orig);
 | 
						||
	    return false;
 | 
						||
	  }
 | 
						||
	++*pp;
 | 
						||
 | 
						||
	if (! stab_demangle_type (minfo, pp, ptype))
 | 
						||
	  return false;
 | 
						||
 | 
						||
	if (ptype != NULL)
 | 
						||
	  {
 | 
						||
	    debug_type class_type;
 | 
						||
 | 
						||
	    class_type = stab_find_tagged_type (minfo->dhandle, minfo->info,
 | 
						||
						name, (int) n,
 | 
						||
						DEBUG_KIND_CLASS);
 | 
						||
	    if (class_type == DEBUG_TYPE_NULL)
 | 
						||
	      return false;
 | 
						||
 | 
						||
	    if (! memberp)
 | 
						||
	      *ptype = debug_make_offset_type (minfo->dhandle, class_type,
 | 
						||
					       *ptype);
 | 
						||
	    else
 | 
						||
	      {
 | 
						||
		/* FIXME: We have no way to record constp or
 | 
						||
                   volatilep.  */
 | 
						||
		*ptype = debug_make_method_type (minfo->dhandle, *ptype,
 | 
						||
						 class_type, args, varargs);
 | 
						||
	      }
 | 
						||
	  }
 | 
						||
      }
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'G':
 | 
						||
      ++*pp;
 | 
						||
      if (! stab_demangle_type (minfo, pp, ptype))
 | 
						||
	return false;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'C':
 | 
						||
      ++*pp;
 | 
						||
      if (! stab_demangle_type (minfo, pp, ptype))
 | 
						||
	return false;
 | 
						||
      if (ptype != NULL)
 | 
						||
	*ptype = debug_make_const_type (minfo->dhandle, *ptype);
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'Q':
 | 
						||
      {
 | 
						||
	const char *hold;
 | 
						||
 | 
						||
	hold = *pp;
 | 
						||
	if (! stab_demangle_qualified (minfo, pp, ptype))
 | 
						||
	  return false;
 | 
						||
      }
 | 
						||
      break;
 | 
						||
 | 
						||
    default:
 | 
						||
      if (! stab_demangle_fund_type (minfo, pp, ptype))
 | 
						||
	return false;
 | 
						||
      break;
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Demangle a fundamental type.  If the ptype argument is not NULL,
 | 
						||
   *ptype is set to the newly allocated type.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_fund_type (minfo, pp, ptype)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char **pp;
 | 
						||
     debug_type *ptype;
 | 
						||
{
 | 
						||
  const char *orig;
 | 
						||
  boolean constp, volatilep, unsignedp, signedp;
 | 
						||
  boolean done;
 | 
						||
 | 
						||
  orig = *pp;
 | 
						||
 | 
						||
  constp = false;
 | 
						||
  volatilep = false;
 | 
						||
  unsignedp = false;
 | 
						||
  signedp = false;
 | 
						||
 | 
						||
  done = false;
 | 
						||
  while (! done)
 | 
						||
    {
 | 
						||
      switch (**pp)
 | 
						||
	{
 | 
						||
	case 'C':
 | 
						||
	  constp = true;
 | 
						||
	  ++*pp;
 | 
						||
	  break;
 | 
						||
 | 
						||
	case 'U':
 | 
						||
	  unsignedp = true;
 | 
						||
	  ++*pp;
 | 
						||
	  break;
 | 
						||
 | 
						||
	case 'S':
 | 
						||
	  signedp = true;
 | 
						||
	  ++*pp;
 | 
						||
	  break;
 | 
						||
 | 
						||
	case 'V':
 | 
						||
	  volatilep = true;
 | 
						||
	  ++*pp;
 | 
						||
	  break;
 | 
						||
 | 
						||
	default:
 | 
						||
	  done = true;
 | 
						||
	  break;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
  switch (**pp)
 | 
						||
    {
 | 
						||
    case '\0':
 | 
						||
    case '_':
 | 
						||
      /* cplus_demangle permits this, but I don't know what it means.  */
 | 
						||
      stab_bad_demangle (orig);
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'v': /* void */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle, "void");
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_void_type (minfo->dhandle);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'x': /* long long */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle,
 | 
						||
					  (unsignedp
 | 
						||
					   ? "long long unsigned int"
 | 
						||
					   : "long long int"));
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'l': /* long */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle,
 | 
						||
					  (unsignedp
 | 
						||
					   ? "long unsigned int"
 | 
						||
					   : "long int"));
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'i': /* int */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle,
 | 
						||
					  (unsignedp
 | 
						||
					   ? "unsigned int"
 | 
						||
					   : "int"));
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 's': /* short */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle,
 | 
						||
					  (unsignedp
 | 
						||
					   ? "short unsigned int"
 | 
						||
					   : "short int"));
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'b': /* bool */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle, "bool");
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_bool_type (minfo->dhandle, 4);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'c': /* char */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle,
 | 
						||
					  (unsignedp
 | 
						||
					   ? "unsigned char"
 | 
						||
					   : (signedp
 | 
						||
					      ? "signed char"
 | 
						||
					      : "char")));
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'w': /* wchar_t */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle, "__wchar_t");
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_int_type (minfo->dhandle, 2, true);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'r': /* long double */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle, "long double");
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_float_type (minfo->dhandle, 8);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'd': /* double */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle, "double");
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_float_type (minfo->dhandle, 8);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'f': /* float */
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  *ptype = debug_find_named_type (minfo->dhandle, "float");
 | 
						||
	  if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	    *ptype = debug_make_float_type (minfo->dhandle, 4);
 | 
						||
	}
 | 
						||
      ++*pp;
 | 
						||
      break;
 | 
						||
 | 
						||
    case 'G':
 | 
						||
      ++*pp;
 | 
						||
      if (! isdigit ((unsigned char) **pp))
 | 
						||
	{
 | 
						||
	  stab_bad_demangle (orig);
 | 
						||
	  return false;
 | 
						||
	}
 | 
						||
      /* Fall through.  */
 | 
						||
    case '0': case '1': case '2': case '3': case '4':
 | 
						||
    case '5': case '6': case '7': case '8': case '9':
 | 
						||
      {
 | 
						||
	const char *hold;
 | 
						||
 | 
						||
	if (! stab_demangle_class (minfo, pp, &hold))
 | 
						||
	  return false;
 | 
						||
	if (ptype != NULL)
 | 
						||
	  {
 | 
						||
	    char *name;
 | 
						||
 | 
						||
	    name = savestring (hold, *pp - hold);
 | 
						||
	    *ptype = debug_find_named_type (minfo->dhandle, name);
 | 
						||
	    if (*ptype == DEBUG_TYPE_NULL)
 | 
						||
	      {
 | 
						||
		/* FIXME: It is probably incorrect to assume that
 | 
						||
                   undefined types are tagged types.  */
 | 
						||
		*ptype = stab_find_tagged_type (minfo->dhandle, minfo->info,
 | 
						||
						hold, *pp - hold,
 | 
						||
						DEBUG_KIND_ILLEGAL);
 | 
						||
	      }
 | 
						||
	    free (name);
 | 
						||
	  }
 | 
						||
      }
 | 
						||
      break;
 | 
						||
 | 
						||
    case 't':
 | 
						||
      if (! stab_demangle_template (minfo, pp))
 | 
						||
	return false;
 | 
						||
      if (ptype != NULL)
 | 
						||
	{
 | 
						||
	  debug_type t;
 | 
						||
 | 
						||
	  /* FIXME: I really don't know how a template should be
 | 
						||
             represented in the current type system.  Perhaps the
 | 
						||
             template should be demangled into a string, and the type
 | 
						||
             should be represented as a named type.  However, I don't
 | 
						||
             know what the base type of the named type should be.  */
 | 
						||
	  t = debug_make_void_type (minfo->dhandle);
 | 
						||
	  t = debug_make_pointer_type (minfo->dhandle, t);
 | 
						||
	  t = debug_name_type (minfo->dhandle, "TEMPLATE", t);
 | 
						||
	  *ptype = t;
 | 
						||
	}
 | 
						||
      break;
 | 
						||
 | 
						||
    default:
 | 
						||
      stab_bad_demangle (orig);
 | 
						||
      return false;
 | 
						||
    }
 | 
						||
 | 
						||
  if (ptype != NULL)
 | 
						||
    {
 | 
						||
      if (constp)
 | 
						||
	*ptype = debug_make_const_type (minfo->dhandle, *ptype);
 | 
						||
      if (volatilep)
 | 
						||
	*ptype = debug_make_volatile_type (minfo->dhandle, *ptype);
 | 
						||
    }
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 | 
						||
 | 
						||
/* Remember a type string in a demangled string.  */
 | 
						||
 | 
						||
static boolean
 | 
						||
stab_demangle_remember_type (minfo, p, len)
 | 
						||
     struct stab_demangle_info *minfo;
 | 
						||
     const char *p;
 | 
						||
     int len;
 | 
						||
{
 | 
						||
  if (minfo->typestring_count >= minfo->typestring_alloc)
 | 
						||
    {
 | 
						||
      minfo->typestring_alloc += 10;
 | 
						||
      minfo->typestrings = ((struct stab_demangle_typestring *)
 | 
						||
			    xrealloc (minfo->typestrings,
 | 
						||
				      (minfo->typestring_alloc
 | 
						||
				       * sizeof *minfo->typestrings)));
 | 
						||
    }
 | 
						||
 | 
						||
  minfo->typestrings[minfo->typestring_count].typestring = p;
 | 
						||
  minfo->typestrings[minfo->typestring_count].len = (unsigned int) len;
 | 
						||
  ++minfo->typestring_count;
 | 
						||
 | 
						||
  return true;
 | 
						||
}
 |