mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-25 18:38:00 +03:00 
			
		
		
		
	PSTACK, libmysqld and MySQL filesystem UPDATE ... ORDER BY DELETE ... ORDER BY New faster fulltext handling Faster compressed keys Makefile.am: Added support for pstack and libmysqld_dir acconfig.h: MySQL filesystem and PSTACK acinclude.m4: MySQL File system client/mysql.cc: Support for --xml configure.in: Pstack, MySQL FS and libmysqld_dir include/ft_global.h: Faster fulltext include/my_pthread.h: Made c++ safe include/myisam.h: Update for faster fulltext include/mysql_com.h: new my_net_read() include/violite.h: libmysqld libmysql/net.c: New protocol that supports big packets myisam/Makefile.am: Faster fulltext myisam/ft_parser.c: Faster fulltext myisam/ft_search.c: Faster fulltext myisam/ft_update.c: Faster fulltext myisam/ftdefs.h: Faster fulltext myisam/mi_check.c: Faster fulltext myisam/mi_open.c: Faster compressed keys myisam/mi_search.c: Faster compressed keys myisam/mi_update.c: Faster compressed keys myisam/myisamdef.h: Faster compressed keys myisam/sort.c: Faster compressed keys mysql-test/mysql-test-run.sh: --skip-innobase and --skip-bdb sql/ChangeLog: Changelog sql/Makefile.am: PSTACK sql/mysql_priv.h: New ORDER BY options and libmysqld sql/mysqld.cc: PSTACK sql/net_serv.cc: New protocol that supports big packets sql/share/estonian/errmsg.txt: New error messages sql/sql_base.cc: Better list_open_tabels sql/sql_delete.cc: ORDER BY for delete sql/sql_lex.cc: Added language convertation of all strings sql/sql_parse.cc: Changes for libmysqld Use new ORDER BY options sql/sql_show.cc: Character set convertations Use new list_open_tables function. sql/sql_update.cc: UPDATE ... ORDER BY sql/sql_yacc.yy: Clean up symbol definitions DELETE .. ORDER BY UPDATE .. ORDER BY sql/table.h: new OPEN_TABLE_LIST structure BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted
		
			
				
	
	
		
			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;
 | ||
| }
 |