This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

alternate __cxa_demangle implementation


Here's a preliminary patch that uses Carlo's demangler for
__cxa_demangle instead of the libibery definitions in cp-demangle.c. I
don't think this patch is ready to go in yet, but I wanted to post the
current status, which is bound to disappoint some people. I still
haven't integrated the testing, for one. For another, the new files
are not formatted for an 80-column display, which needs to be
done. Also, I get trailing bits in some demangled names when I run
'make check-abi':

	_ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_
	demangled symbol
	std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)!

Note the last '!'.

I'm unsure what to do with the debugging hooks, but leaving in
references to libcwd is not going to work.

I'm not quite sure "session" really captures what is being attempted
here. I would like a bit more time on this, I think. I did want to
post this before the holiday season though.

-benjamin



2002-12-20  Benjamin Kosnik  <bkoz@redhat.com>

	* libsupc++/Makefile.am (sources): Add demangle.cc.
	(c_sources): Remove.
	(libsupc___la_SOURCES): And here.
	(libsupc__convenience_la_SOURCES): And here.
	(cxa_demangle.*): Remove rules.
	(dyn-string.*): Same.
	(AM_CXXFLAGS): Remove -fno-implicit-templates.
	* libsupc++/Makefile.in: Regenerate.

2002-12-20  Carlo Wood  <carlo@alinoe.com>
	
	* libsupc++/demangle.h: New file.	
	* libsupc++/demangle.cc: New file.

Index: libsupc++/Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/libsupc++/Makefile.am,v
retrieving revision 1.37
diff -c -p -r1.37 Makefile.am
*** libsupc++/Makefile.am	16 Dec 2002 19:02:00 -0000	1.37
--- libsupc++/Makefile.am	23 Dec 2002 16:51:26 -0000
*************** CONFIG_CXXFLAGS = \
*** 55,60 ****
--- 55,62 ----
  WARN_CXXFLAGS = \
  	@WARN_FLAGS@ $(WERROR) -fdiagnostics-show-location=once
  
+ LIBSUPCXX_CXXFLAGS = @LIBSUPCXX_PICFLAGS@
+ 
  # Use common includes from acinclude.m4/GLIBCPP_EXPORT_INCLUDES
  GLIBCPP_INCLUDES = @GLIBCPP_INCLUDES@
  LIBSUPCXX_INCLUDES = @LIBSUPCXX_INCLUDES@
*************** INCLUDES = \
*** 66,80 ****
  headers = \
  	exception new typeinfo cxxabi.h exception_defines.h 
  
- c_sources = \
- 	cxa_demangle.c \
- 	dyn-string.c 
- 
  sources = \
  	del_op.cc \
  	del_opnt.cc \
  	del_opv.cc \
  	del_opvnt.cc \
  	eh_alloc.cc \
  	eh_aux_runtime.cc \
  	eh_catch.cc \
--- 68,79 ----
  headers = \
  	exception new typeinfo cxxabi.h exception_defines.h 
  
  sources = \
  	del_op.cc \
  	del_opnt.cc \
  	del_opv.cc \
  	del_opvnt.cc \
+ 	demangle.cc \
  	eh_alloc.cc \
  	eh_aux_runtime.cc \
  	eh_catch.cc \
*************** sources = \
*** 95,108 ****
  	tinfo2.cc \
  	vec.cc
  
! libsupc___la_SOURCES = $(sources) $(c_sources)
! libsupc__convenience_la_SOURCES = $(sources) $(c_sources)
  
  glibcppinstalldir = @gxx_include_dir@
  glibcppinstall_HEADERS = $(headers)
  
- LIBSUPCXX_CXXFLAGS = $(LIBSUPCXX_PICFLAGS)
- 
  # Use special rules for pulling things out of libiberty.  These
  # objects should be compiled with the "C" compiler, not the C++
  # compiler, and also should not use the C++ includes.
--- 94,105 ----
  	tinfo2.cc \
  	vec.cc
  
! libsupc___la_SOURCES = $(sources) 
! libsupc__convenience_la_SOURCES = $(sources) 
  
  glibcppinstalldir = @gxx_include_dir@
  glibcppinstall_HEADERS = $(headers)
  
  # Use special rules for pulling things out of libiberty.  These
  # objects should be compiled with the "C" compiler, not the C++
  # compiler, and also should not use the C++ includes.
*************** C_COMPILE = \
*** 110,143 ****
  	$(CC) $(DEFS) $(GCC_INCLUDES) \
  	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
  
- cxa_demangle.c:
- 	rm -f $@
- 	$(LN_S) $(toplevel_srcdir)/libiberty/cp-demangle.c $@
- cxa_demangle.lo: cxa_demangle.c
- 	$(LTCOMPILE) -DIN_GLIBCPP_V3 -Wno-error -c $<
- cxa_demangle.o: cxa_demangle.c
- 	$(C_COMPILE) -DIN_GLIBCPP_V3 -Wno-error -c $<
- dyn-string.c:
- 	rm -f $@
- 	$(LN_S) $(toplevel_srcdir)/libiberty/dyn-string.c $@
- dyn-string.lo: dyn-string.c
- 	$(LTCOMPILE) -DIN_GLIBCPP_V3 -Wno-error -c $<
- dyn-string.o: dyn-string.c
- 	$(C_COMPILE) -DIN_GLIBCPP_V3 -Wno-error -c $<
- 
  # LTCOMPILE is copied from LTCXXCOMPILE below.
  LTCOMPILE = $(LIBTOOL) --tag CC --tag disable-shared --mode=compile $(CC) \
  	    $(DEFS) $(GCC_INCLUDES) $(LIBSUPCXX_PICFLAGS) \
              $(AM_CPPFLAGS) $(CPPFLAGS) 
  
- 
  # AM_CXXFLAGS needs to be in each subdirectory so that it can be
  # modified in a per-library or per-sub-library way.  Need to manually
  # set this option because CONFIG_CXXFLAGS has to be after
  # OPTIMIZE_CXXFLAGS on the compile line so that -O2 can be overridden
! # as the occasion call for it. (ie, --enable-debug)
  AM_CXXFLAGS = \
- 	-fno-implicit-templates \
  	$(LIBSUPCXX_CXXFLAGS) \
  	$(WARN_CXXFLAGS) \
  	$(OPTIMIZE_CXXFLAGS) \
--- 107,123 ----
  	$(CC) $(DEFS) $(GCC_INCLUDES) \
  	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
  
  # LTCOMPILE is copied from LTCXXCOMPILE below.
  LTCOMPILE = $(LIBTOOL) --tag CC --tag disable-shared --mode=compile $(CC) \
  	    $(DEFS) $(GCC_INCLUDES) $(LIBSUPCXX_PICFLAGS) \
              $(AM_CPPFLAGS) $(CPPFLAGS) 
  
  # AM_CXXFLAGS needs to be in each subdirectory so that it can be
  # modified in a per-library or per-sub-library way.  Need to manually
  # set this option because CONFIG_CXXFLAGS has to be after
  # OPTIMIZE_CXXFLAGS on the compile line so that -O2 can be overridden
! # as the occasion call for it. 
  AM_CXXFLAGS = \
  	$(LIBSUPCXX_CXXFLAGS) \
  	$(WARN_CXXFLAGS) \
  	$(OPTIMIZE_CXXFLAGS) \
Index: libsupc++/demangle.cc
===================================================================
RCS file: libsupc++/demangle.cc
diff -N libsupc++/demangle.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- libsupc++/demangle.cc	23 Dec 2002 16:51:26 -0000
***************
*** 0 ****
--- 1,168 ----
+ // C++ IA64 / g++ v3 demangler  -*- C++ -*-
+ 
+ // Copyright (C) 2002 Free Software Foundation, Inc.
+ // Written by Carlo Wood <carlo@alinoe.com>
+ //
+ // This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
+ // any later version.
+ 
+ // This library 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 library; see the file COPYING.  If not, write to the Free
+ // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ // USA.
+ 
+ // As a special exception, you may use this file as part of a free software
+ // library without restriction.  Specifically, if other files instantiate
+ // templates or use macros or inline functions from this file, or you compile
+ // this file and link it with other files to produce an executable, this
+ // file does not by itself cause the resulting executable to be covered by
+ // the GNU General Public License.  This exception does not however
+ // invalidate any other reasons why the executable file might be covered by
+ // the GNU General Public License.
+ 
+ #include <cxxabi.h>
+ #include "demangle.h"
+ 
+ // __cxa_demangle
+ //
+ // Demangle a C++ symbol or type name.
+ //
+ // `mangled-name' is a pointer to a null-terminated array of characters.
+ // It may be either an external name, i.e. with a "_Z" prefix, or an
+ // internal NTBS mangling, e.g. of a type for type_info.
+ //
+ // `buf' may be null.  If it is non-null, then n must also be nonnull,
+ // and buf is a pointer to an array, of at least *n characters, that
+ // was allocated using malloc.
+ //
+ // `status' points to an int that is used as an error indicator. It is
+ // permitted to be null, in which case the user just doesn't get any
+ // detailed error information. 
+ //
+ // Returns: a pointer to a null-terminated array of characters, the
+ //          demangled name.  Or NULL in case of failure.
+ //
+ // If there is an error in demangling, the return value is a null pointer.
+ // The user can examine *status to find out what kind of error occurred.
+ // Meaning of error indications:
+ //
+ //     * 0: success
+ //     * -1: memory allocation failure
+ //     * -2: invalid mangled name
+ //     * -3: invalid arguments (e.g. buf nonnull and n null) 
+ //
+ namespace __cxxabiv1 
+ {
+   namespace 
+   {
+     char* const error = 0;
+     enum status_codes 
+       {
+ 	success = 0,
+ 	memory_allocation_failure = -1,
+ 	invalid_mangled_name = -2,
+ 	invalid_argument = -3
+       };
+ 
+     inline char*
+     failure(status_codes error_code, int* status)
+     {
+       if (status)
+ 	*status = error_code;
+       return error;
+     }
+ 
+     char*
+     finish(char const* demangled_name, size_t demangled_name_size, char* buf, 
+ 	   size_t* n, int* status)
+     {
+       if (!buf || *n < demangled_name_size + 1)
+ 	{
+ 	  if (n)
+ 	    *n = demangled_name_size + 1;
+ 	  buf = (char*)realloc(buf, demangled_name_size + 1);
+ 	  if (!buf)
+ 	    return failure(memory_allocation_failure, status);
+ 	}
+       if (status)
+ 	*status = success;
+       std::strncpy(buf, demangled_name, demangled_name_size);
+       return buf;
+     }
+   } // namespace
+ 
+   char*
+   __cxa_demangle(char const* mangled_name, char* buf, std::size_t* n, 
+ 		 int* status)
+   {
+     using namespace __gnu_cxx;
+     typedef demangler::session<std::allocator<char> > session_type;
+ 
+     if (!mangled_name || (buf && !n))
+       return failure(invalid_argument, status);
+ 
+     std::string result;
+     if (mangled_name[0] == '_')		
+       {
+ 	// External name?
+ 	if (mangled_name[1] == 'Z')		
+ 	  {
+ 	    // C++ name?
+ 	    int cnt = session_type::decode_encoding(result, mangled_name + 2, 
+ 						    INT_MAX);
+ 	    if (cnt < 0 || mangled_name[cnt + 2] != 0)
+ 	      return failure(invalid_mangled_name, status);
+ 	    return finish(result.data(), result.size(), buf, n, status);
+ 	  }
+ 	else if (mangled_name[1] == 'G')	
+ 	  {
+ 	    // Possible _GLOBAL__ extension?
+ 	    if (!std::strncmp(mangled_name, "_GLOBAL__", 9) 
+ 		&& (mangled_name[9] == 'D' || mangled_name[9] == 'I')
+ 		&& mangled_name[10] == '_' && mangled_name[11] == '_' 
+ 		&& mangled_name[12] == 'Z')
+ 	      {
+ 		if (mangled_name[9] == 'D')
+ 		  result.assign("global destructors keyed to ", 28);
+ 		else
+ 		  result.assign("global constructors keyed to ", 29);
+ 		int cnt = session_type::decode_encoding(result, 
+ 							mangled_name + 13, 
+ 							INT_MAX);
+ 		if (cnt < 0 || mangled_name[cnt + 13] != 0)
+ 		  return failure(invalid_mangled_name, status);
+ 		return finish(result.data(), result.size(), buf, n, status);
+ 	      }
+ 	  }
+       }
+ 
+     // Ambiguities are possible between extern "C" object names and
+     // internal built-in type names, e.g. "i" may be either an object
+     // named "i" or the built-in "int" type.  Such ambiguities should
+     // be resolved to user names over built-in names.  Builtin types
+     // are any single lower case character.  Any other single
+     // character is not a mangled type so we can treat those the same
+     // here.
+     if (mangled_name[1] == 0)
+       return finish(mangled_name, 1, buf, n, status);
+ 
+     // Not a built-in type or external name, try to demangle input as
+     // NTBS mangled type name.
+     session_type demangler_session(mangled_name, INT_MAX);
+     if (!demangler_session.decode_type(result) 
+ 	|| demangler_session.remaining_input_characters())
+       {
+ 	// Failure to demangle, assume extern "C" name.
+ 	result = mangled_name;		
+       }
+     return finish(result.data(), result.size(), buf, n, status);
+   }
+ } // namespace __cxxabiv1
Index: libsupc++/demangle.h
===================================================================
RCS file: libsupc++/demangle.h
diff -N libsupc++/demangle.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- libsupc++/demangle.h	23 Dec 2002 16:51:28 -0000
***************
*** 0 ****
--- 1,2089 ----
+ // C++ IA64 / g++ v3 demangler  -*- C++ -*-
+ 
+ // Copyright (C) 2002 Free Software Foundation, Inc.
+ // Written by Carlo Wood <carlo@alinoe.com>
+ //
+ // This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
+ // any later version.
+ 
+ // This library 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 library; see the file COPYING.  If not, write to the Free
+ // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ // USA.
+ 
+ // As a special exception, you may use this file as part of a free software
+ // library without restriction.  Specifically, if other files instantiate
+ // templates or use macros or inline functions from this file, or you compile
+ // this file and link it with other files to produce an executable, this
+ // file does not by itself cause the resulting executable to be covered by
+ // the GNU General Public License.  This exception does not however
+ // invalidate any other reasons why the executable file might be covered by
+ // the GNU General Public License.
+ 
+ #ifndef __DEMANGLER_H
+ #define __DEMANGLER_H
+ 
+ #include <limits>
+ #include <vector>
+ #include <string>
+ #include <cctype>
+ 
+ #ifndef CWDEBUG
+ #define _GLIBCPP_DEMANGLER_RETURN  return M_result
+ #define _GLIBCPP_DEMANGLER_FAILURE do { M_result = false; return false; } while(0)
+ #define _GLIBCPP_DEMANGLER_DEBUG(x)
+ #define _GLIBCPP_DEMANGLER_DOUT(cntrl, data)
+ #define _GLIBCPP_DEMANGLER_DOUT_ENTERING(x)
+ #endif
+ 
+ namespace __gnu_cxx 
+ {
+   namespace demangler 
+     {
+       enum substitution_nt 
+ 	{
+ 	  type,
+ 	  template_template_param,
+ 	  nested_name_prefix,
+ 	  nested_name_template_prefix,
+ 	  unscoped_template_name,
+ 	};
+       
+       struct substitution_st 
+       {
+ 	int M_start_pos;
+ 	substitution_nt M_type;
+ 	int M_number_of_prefixes;
+ 	
+ 	substitution_st(int start_pos, substitution_nt type, 
+ 			int number_of_prefixes) :
+ 	M_start_pos(start_pos), M_type(type), 
+ 	M_number_of_prefixes(number_of_prefixes) { }
+       };
+ 
+       enum simple_qualifier_nt 
+ 	{
+ 	  complex_or_imaginary = 'G',
+ 	  pointer = 'P',
+ 	  reference = 'R'
+ 	};
+       
+       enum cv_qualifier_nt 
+ 	{
+ 	  cv_qualifier = 'K'
+ 	};
+       
+       enum param_qualifier_nt 
+ 	{
+ 	  vendor_extension = 'U',
+ 	  array = 'A', 
+ 	  pointer_to_member = 'M'
+ 	};
+       
+       template<typename Allocator>
+         class qualifier;
+ 
+       template<typename Allocator>
+       class qualifier_list;
+ 
+       template<typename Allocator>
+ 	class session;
+       
+       template<typename Allocator>
+ 	class qualifier 
+ 	{
+ 	  typedef std::basic_string<char, std::char_traits<char>, Allocator>
+ 	    string_type;
+ 
+ 	private:
+ 	  char 				M_qualifier1;
+ 	  char 				M_qualifier2;
+ 	  char 				M_qualifier3;
+ 	  mutable unsigned char 	M_cnt;
+ 	  string_type  			M_optional_type;
+ 	  int 				M_start_pos;
+ 	  bool 				M_part_of_substitution;
+ 
+ 	public:
+ 	  qualifier(int start_pos, simple_qualifier_nt simple_qualifier, 
+ 		    int inside_substitution) 
+ 	  : M_qualifier1(simple_qualifier), M_start_pos(start_pos),
+ 	  M_part_of_substitution(inside_substitution) { }
+ 
+ 	  qualifier(int start_pos, cv_qualifier_nt cv_qualifier, 
+ 		    char const* start, int count, int inside_substitution) 
+ 	  : M_qualifier1(start[0]), 
+ 	  M_qualifier2((count > 1) ? start[1] : '\0'),
+ 	  M_qualifier3((count > 2) ? start[2] : '\0'), M_start_pos(start_pos),
+ 	  M_part_of_substitution(inside_substitution) { }
+ 
+ 	  qualifier(int start_pos, param_qualifier_nt param_qualifier, 
+ 		    string_type optional_type, int inside_substitution)
+ 	  : M_qualifier1(param_qualifier),M_optional_type(optional_type),
+ 	  M_start_pos(start_pos), 
+ 	  M_part_of_substitution(inside_substitution) { }
+ 
+ 	  int 
+ 	  start_pos(void) const { return M_start_pos; }
+ 
+ 	  char 
+ 	  first_qualifier(void) const { M_cnt = 1; return M_qualifier1; }
+ 
+ 	  char 
+ 	  next_qualifier(void) const 
+ 	  { 
+ 	    return (++M_cnt == 2) ? M_qualifier2 : (M_cnt == 3) ? M_qualifier3 : 0; 
+ 	  }
+ 
+ 	  string_type const& 
+ 	  optional_type(void) const { return M_optional_type; }
+ 
+ 	  bool 
+ 	  part_of_substitution(void) const { return M_part_of_substitution; }
+ 	};
+       
+       template<typename Allocator>
+ 	class qualifier_list 
+ 	{
+ 	  typedef std::basic_string<char, std::char_traits<char>, Allocator>
+ 	    string_type;
+ 
+ 	private:
+ 	  bool M_printing_suppressed;
+ 	  std::vector<qualifier<Allocator>, Allocator> M_qualifier_starts;
+ 	  session<Allocator>& M_demangler;
+ 
+ 	public:
+ 	  qualifier_list(session<Allocator>& demangler_obj) : M_printing_suppressed(false), M_demangler(demangler_obj) { }
+ 
+ 	  void 
+ 	  add_qualifier_start(simple_qualifier_nt simple_qualifier, int start_pos, int inside_substitution)
+ 	  { M_qualifier_starts.push_back(qualifier<Allocator>(start_pos, simple_qualifier, inside_substitution)); }
+ 
+ 	  void 
+ 	  add_qualifier_start(cv_qualifier_nt cv_qualifier, int start_pos, int count, int inside_substitution)
+ 	  { M_qualifier_starts.push_back(qualifier<Allocator>(start_pos, cv_qualifier, &M_demangler.M_str[start_pos], count, inside_substitution)); }
+ 
+ 	  void 
+ 	  add_qualifier_start(param_qualifier_nt param_qualifier, int start_pos, string_type optional_type, int inside_substitution)
+         { M_qualifier_starts.push_back(qualifier<Allocator>(start_pos, param_qualifier, optional_type, inside_substitution)); }
+ 
+ 	  void 
+ 	  decode_qualifiers(string_type& output);
+ 
+ 	  bool 
+ 	  suppressed(void) const { return M_printing_suppressed; }
+ 
+ 	  void 
+ 	  printing_suppressed(void) { M_printing_suppressed = true; }
+ 
+ 	  size_t 
+ 	  size(void) const { return M_qualifier_starts.size(); }
+ 	};
+ 
+       template<typename Allocator>
+         class session 
+ 	{
+ 	  typedef std::basic_string<char, std::char_traits<char>, Allocator>
+ 	    string_type;
+ 
+ 	  friend class qualifier_list<Allocator>;
+ 
+ 	private:
+ 	  char const* M_str;
+ 	  int M_pos;
+ 	  int M_maxpos;
+ 	  bool M_result;
+ 	  int M_inside_template_args;
+ 	  int M_inside_type;
+ 	  int M_inside_substitution;
+ 	  bool M_saw_destructor;
+ 	  bool M_name_is_cdtor;
+ 	  bool M_name_is_template;
+ 	  bool M_name_is_conversion_operator;
+ 	  bool M_template_args_need_space;
+ 	  string_type M_function_name;
+ 	  std::vector<int, Allocator> M_template_arg_pos;
+ 	  int M_template_arg_pos_offset;
+ 	  std::vector<substitution_st, Allocator> M_substitutions_pos;
+ #ifdef CWDEBUG
+ 	  bool M_inside_add_substitution;
+ #endif
+ 
+   public:
+ 	  explicit session(char const* in, int len) 
+ 	  : M_str(in), M_pos(0), M_maxpos(len - 1), M_result(true), M_inside_template_args(0), M_inside_type(0), M_inside_substitution(0),
+ 	M_saw_destructor(false), M_name_is_cdtor(false), M_name_is_template(false), M_name_is_conversion_operator(false),
+ 	M_template_args_need_space(false), M_template_arg_pos_offset(0)
+ #ifdef CWDEBUG
+         , M_inside_add_substitution(false)
+ #endif
+ 	{ }
+ 
+ 	  static int 
+ 	  decode_encoding(string_type& output, char const* input, int len);
+ 
+ 	  bool 
+ 	  decode_type(string_type& output, 
+ 		      qualifier_list<Allocator>* qualifiers = NULL);
+ 
+ 	  bool 
+ 	  remaining_input_characters(void) const { return (current() != 0); }
+ 
+ 	private:
+ 	  char 
+ 	  current(void) const { return (M_pos > M_maxpos) ? 0 : M_str[M_pos]; }
+ 
+ 	  char 
+ 	  next(void) { return (M_pos >= M_maxpos) ? 0 : M_str[++M_pos]; }
+ 
+ 	  char 
+ 	  eat_current(void) { return (M_pos > M_maxpos) ? 0 : M_str[M_pos++]; }
+ 
+ 	  void 
+ 	  store(int& saved_pos) { saved_pos = M_pos; }
+ 
+ 	  void 
+ 	  restore(int saved_pos) { M_pos = saved_pos; M_result = true; }
+ 
+ 	  void 
+ 	  add_substitution(int start_pos, substitution_nt sub_type, 
+ 			   int number_of_prefixes);
+ 	  
+ 	  bool 
+ 	  decode_bare_function_type(string_type& output);
+ 	  bool decode_builtin_type(string_type& output);
+ 	  bool decode_call_offset(string_type& output);
+ 	  bool decode_class_enum_type(string_type& output);
+ 	  bool decode_expression(string_type& output);
+ 	  bool decode_literal(string_type& output);
+ 	  bool decode_local_name(string_type& output);
+ 	  bool decode_name(string_type& output,
+ 			   string_type& nested_name_qualifiers);
+ 	  bool decode_nested_name(string_type& output,
+ 				  string_type& qualifiers);
+ 	  bool decode_number(string_type& output);
+ 	  bool decode_operator_name(string_type& output);
+ 	  bool decode_source_name(string_type& output);
+ 	  bool decode_substitution(string_type& output,
+ 				   qualifier_list<Allocator>* qualifiers = NULL);
+ 	  bool decode_template_args(string_type& output);
+ 	  bool decode_template_param(string_type& output,
+ 				     qualifier_list<Allocator>* qualifiers = NULL);
+ 	  bool decode_unqualified_name(string_type& output);
+ 	  bool decode_unscoped_name(string_type& output);
+ 	  bool decode_decimal_integer(string_type& output);
+ 	  bool decode_special_name(string_type& output);
+ 	};
+       
+       template<typename Allocator>
+ #ifndef CWDEBUG
+       inline
+ #endif
+       void session<Allocator>::
+       add_substitution(int start_pos, substitution_nt sub_type, int number_of_prefixes = 0)
+   {
+     if (!M_inside_substitution)
+     {
+ #ifdef CWDEBUG
+       if (M_inside_add_substitution)
+ 	return;
+ #endif
+       M_substitutions_pos.push_back(substitution_st(start_pos, sub_type, number_of_prefixes));
+ #ifdef CWDEBUG
+       if (!DEBUGCHANNELS::dc::demangler.is_on())
+ 	return;
+       string_type substitution_name("S");
+       int n = M_substitutions_pos.size() - 1;
+       if (n > 0)
+ 	substitution_name += (n <= 10) ? (char)(n + '0' - 1) : (char)(n + 'A' - 11);
+       substitution_name += '_';
+       string_type subst;
+       int saved_pos = M_pos;
+       M_pos = start_pos;
+       M_inside_add_substitution = true;
+       _GLIBCPP_DEMANGLER_DEBUG( dc::demangler.off() );
+       switch(sub_type)
+       {
+ 	case type:
+ 	  decode_type(subst);
+ 	  break;
+ 	case template_template_param:
+ 	  decode_template_param(subst);
+ 	  break;
+ 	case nested_name_prefix:
+ 	case nested_name_template_prefix:
+ 	  for (int cnt = number_of_prefixes; cnt > 0; --cnt)
+ 	  {
+ 	    if (current() == 'I')
+ 	    {
+ 	      subst += ' ';
+ 	      decode_template_args(subst);
+ 	    }
+ 	    else
+ 	    {
+ 	      if (cnt < number_of_prefixes)
+ 		subst += "::";
+ 	      if (current() == 'S')
+ 		decode_substitution(subst);
+ 	      else
+ 		decode_unqualified_name(subst);
+ 	    }
+ 	  }
+ 	  break;
+ 	case unscoped_template_name:
+ 	  decode_unscoped_name(subst);
+ 	  break;
+       }
+       M_pos = saved_pos;
+       _GLIBCPP_DEMANGLER_DEBUG( dc::demangler.on() );
+       _GLIBCPP_DEMANGLER_DOUT(dc::demangler, "Adding substitution " << substitution_name
+ 	  << " : " << subst
+ 	  << " (from " << location_ct((char*)__builtin_return_address(0) + builtin_return_address_offset)
+ 	  << " <- " << location_ct((char*)__builtin_return_address(1) + builtin_return_address_offset)
+ 	  << " <- " << location_ct((char*)__builtin_return_address(2) + builtin_return_address_offset)
+ 	  << ").");
+       M_inside_add_substitution = false;
+ #endif
+     }
+   }
+ 
+ //
+ // <decimal-integer> ::= 0
+ //                   ::= 1|2|3|4|5|6|7|8|9 [<digit>+]
+ // <digit>           ::= 0|1|2|3|4|5|6|7|8|9
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_decimal_integer(string_type& output)
+   {
+     char c = current();
+     if (c == '0')
+     {
+       output += '0';
+       eat_current();
+     }
+     else if (!std::isdigit(c))
+       M_result = false;
+     else
+     {
+       do
+       {
+         output += c;
+       }
+       while (std::isdigit((c = next())));
+     }
+     return M_result;
+   }
+ 
+ // <number> ::= [n] <decimal-integer>
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_number(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_number");
+     if (current() != 'n')
+       decode_decimal_integer(output);
+     else
+     {
+       output += '-';
+       eat_current();
+       decode_decimal_integer(output);
+     }
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <builtin-type> ::= v  # void
+ //                ::= w  # wchar_t
+ //                ::= b  # bool
+ //                ::= c  # char
+ //                ::= a  # signed char
+ //                ::= h  # unsigned char
+ //                ::= s  # short
+ //                ::= t  # unsigned short
+ //                ::= i  # int
+ //                ::= j  # unsigned int
+ //                ::= l  # long
+ //                ::= m  # unsigned long
+ //                ::= x  # long long, __int64
+ //                ::= y  # unsigned long long, __int64
+ //                ::= n  # __int128
+ //                ::= o  # unsigned __int128
+ //                ::= f  # float
+ //                ::= d  # double
+ //                ::= e  # long double, __float80
+ //                ::= g  # __float128
+ //                ::= z  # ellipsis
+ //                ::= u <source-name>    # vendor extended type
+ //
+ char const* const builtin_type_c[26] = {
+   "signed char",	// a
+   "bool",		// b
+   "char",		// c
+   "double",		// d
+   "long double",	// e
+   "float",		// f
+   "__float128",		// g
+   "unsigned char",	// h
+   "int",		// i
+   "unsigned int",	// j
+   NULL,			// k
+   "long",		// l
+   "unsigned long",	// m
+   "__int128",		// n
+   "unsigned __int128",	// o
+   NULL,			// p
+   NULL,			// q
+   NULL,			// r
+   "short",		// s
+   "unsigned short",	// t
+   NULL,			// u
+   "void",		// v
+   "wchar_t",		// w
+   "long long",		// x
+   "unsigned long long",	// y
+   "..."			// z
+ };
+ 
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_builtin_type(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_builtin_type");
+     char const* bt;
+     if (!islower(current()) || !(bt = builtin_type_c[current() - 'a']))
+       _GLIBCPP_DEMANGLER_FAILURE;
+     output += bt;
+     eat_current();
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <class-enum-type> ::= <name>
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_class_enum_type(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_class_enum_type");
+     string_type nested_name_qualifiers;
+     if (!decode_name(output, nested_name_qualifiers))
+       _GLIBCPP_DEMANGLER_FAILURE;
+     output += nested_name_qualifiers;
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <substitution> ::= S <seq-id> _
+ //                ::= S_
+ //                ::= St # ::std::
+ //                ::= Sa # ::std::allocator
+ //                ::= Sb # ::std::basic_string
+ //                ::= Ss # ::std::basic_string<char, std::char_traits<char>, std::allocator<char> >
+ //                ::= Si # ::std::basic_istream<char,  std::char_traits<char> >
+ //                ::= So # ::std::basic_ostream<char,  std::char_traits<char> >
+ //                ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+ //
+ // <seq-id> ::= 0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z [<seq-id>]	# Base 36 number
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_substitution(string_type& output, qualifier_list<Allocator>* qualifiers)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_substitution");
+     unsigned int value = 0;
+     char c = next();
+     if (c != '_')
+     {
+       switch(c)
+       {
+ 	case 'a':
+ 	{
+ 	  output += "std::allocator";
+ 	  if (!M_inside_template_args)
+ 	  {
+ 	    M_function_name = "allocator";
+ 	    M_name_is_template = true;
+ 	    M_name_is_cdtor = false;
+ 	    M_name_is_conversion_operator = false;
+ 	  }
+ 	  eat_current();
+ 	  if (qualifiers)
+ 	    qualifiers->printing_suppressed();
+ 	  _GLIBCPP_DEMANGLER_RETURN;
+ 	}
+ 	case 'b':
+ 	{
+ 	  output += "std::basic_string";
+ 	  if (!M_inside_template_args)
+ 	  {
+ 	    M_function_name = "basic_string";
+ 	    M_name_is_template = true;
+ 	    M_name_is_cdtor = false;
+ 	    M_name_is_conversion_operator = false;
+ 	  }
+ 	  eat_current();
+ 	  if (qualifiers)
+ 	    qualifiers->printing_suppressed();
+ 	  _GLIBCPP_DEMANGLER_RETURN;
+ 	}
+ 	case 'd':
+ 	  output += "std::iostream";
+ 	  if (!M_inside_template_args)
+ 	  {
+ 	    M_function_name = "iostream";
+ 	    M_name_is_template = true;
+ 	    M_name_is_cdtor = false;
+ 	    M_name_is_conversion_operator = false;
+ 	  }
+ 	  eat_current();
+ 	  if (qualifiers)
+ 	    qualifiers->printing_suppressed();
+ 	  _GLIBCPP_DEMANGLER_RETURN;
+ 	case 'i':
+ 	  output += "std::istream";
+ 	  if (!M_inside_template_args)
+ 	  {
+ 	    M_function_name = "istream";
+ 	    M_name_is_template = true;
+ 	    M_name_is_cdtor = false;
+ 	    M_name_is_conversion_operator = false;
+ 	  }
+ 	  eat_current();
+ 	  if (qualifiers)
+ 	    qualifiers->printing_suppressed();
+ 	  _GLIBCPP_DEMANGLER_RETURN;
+ 	case 'o':
+ 	  output += "std::ostream";
+ 	  if (!M_inside_template_args)
+ 	  {
+ 	    M_function_name = "ostream";
+ 	    M_name_is_template = true;
+ 	    M_name_is_cdtor = false;
+ 	    M_name_is_conversion_operator = false;
+ 	  }
+ 	  eat_current();
+ 	  if (qualifiers)
+ 	    qualifiers->printing_suppressed();
+ 	  _GLIBCPP_DEMANGLER_RETURN;
+ 	case 's':
+ 	  output += "std::string";
+ 	  if (!M_inside_template_args)
+ 	  {
+ 	    M_function_name = "string";
+ 	    M_name_is_template = true;
+ 	    M_name_is_cdtor = false;
+ 	    M_name_is_conversion_operator = false;
+ 	  }
+ 	  eat_current();
+ 	  if (qualifiers)
+ 	    qualifiers->printing_suppressed();
+ 	  _GLIBCPP_DEMANGLER_RETURN;
+ 	case 't':
+ 	  output += "std";
+ 	  eat_current();
+ 	  if (qualifiers)
+ 	    qualifiers->printing_suppressed();
+ 	  _GLIBCPP_DEMANGLER_RETURN;
+ 	default:
+ 	  for(;; c = next())
+ 	  {
+ 	    if (std::isdigit(c))
+ 	      value = value * 36 + c - '0';
+ 	    else if (isupper(c))
+ 	      value = value * 36 + c - 'A' + 10;
+ 	    else if (c == '_')
+ 	      break;
+ 	    else
+ 	      _GLIBCPP_DEMANGLER_FAILURE;
+ 	  }
+ 	  ++value;
+ 	  break;
+       }
+     }
+     eat_current();
+     if (value >= M_substitutions_pos.size() ||
+         M_inside_type > 20)				// Rather than core dump.
+       _GLIBCPP_DEMANGLER_FAILURE;
+     ++M_inside_substitution;
+     int saved_pos = M_pos;
+     substitution_st& substitution(M_substitutions_pos[value]);
+     M_pos = substitution.M_start_pos;
+     switch(substitution.M_type)
+     {
+       case type:
+ 	decode_type(output, qualifiers);
+ 	break;
+       case template_template_param:
+         decode_template_param(output, qualifiers);
+         break;
+       case nested_name_prefix:
+       case nested_name_template_prefix:
+         for (int cnt = substitution.M_number_of_prefixes; cnt > 0; --cnt)
+ 	{
+ 	  if (current() == 'I')
+ 	  {
+ 	    if (M_template_args_need_space)
+ 	      output += ' ';
+ 	    M_template_args_need_space = false;
+ 	    if (!decode_template_args(output))
+ 	      _GLIBCPP_DEMANGLER_FAILURE;
+ 	  }
+ 	  else
+ 	  {
+ 	    if (cnt < substitution.M_number_of_prefixes)
+ 	      output += "::";
+ 	    if (current() == 'S')
+ 	    {
+ 	      if (!decode_substitution(output))
+ 		_GLIBCPP_DEMANGLER_FAILURE;
+ 	    }
+ 	    else if (!decode_unqualified_name(output))
+ 	      _GLIBCPP_DEMANGLER_FAILURE;
+ 	  }
+ 	}
+ 	if (qualifiers)
+ 	  qualifiers->printing_suppressed();
+         break;
+       case unscoped_template_name:
+         decode_unscoped_name(output);
+ 	if (qualifiers)
+ 	  qualifiers->printing_suppressed();
+         break;
+     }
+     M_pos = saved_pos;
+     --M_inside_substitution;
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <template-param> ::= T_				# first template parameter
+ //                  ::= T <parameter-2 non-negative number> _
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_template_param(string_type& output, qualifier_list<Allocator>* qualifiers)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_template_parameter");
+     if (current() != 'T')
+       _GLIBCPP_DEMANGLER_FAILURE;
+     unsigned int value = 0;
+     char c;
+     if ((c = next()) != '_')
+     {
+       while(std::isdigit(c))
+       {
+         value = value * 10 + c - '0';
+ 	c = next();
+       }
+       ++value;
+     }
+     if (eat_current() != '_')
+       _GLIBCPP_DEMANGLER_FAILURE;
+     value += M_template_arg_pos_offset;
+     if (value >= M_template_arg_pos.size())
+       _GLIBCPP_DEMANGLER_FAILURE;
+     int saved_pos = M_pos;
+     M_pos = M_template_arg_pos[value];
+     if (M_inside_type > 20)		// Rather than core dump.
+       _GLIBCPP_DEMANGLER_FAILURE;
+     ++M_inside_substitution;
+     if (current() == 'X')
+     {
+       eat_current();
+       decode_expression(output);
+     }
+     else if (current() == 'L')
+       decode_literal(output);
+     else
+       decode_type(output, qualifiers);
+     --M_inside_substitution;
+     M_pos = saved_pos;
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_literal(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_literal");
+     eat_current();	// Eat the 'L'.
+     if (current() == '_')
+     {
+       if (next() != 'Z')
+ 	_GLIBCPP_DEMANGLER_FAILURE;
+       eat_current();
+       if ((M_pos += decode_encoding(output, M_str + M_pos, M_maxpos - M_pos + 1)) < 0)
+ 	_GLIBCPP_DEMANGLER_FAILURE;
+     }
+     else
+     {
+       // Special cases
+       if (current() == 'b')
+       {
+         if (next() == '0')
+ 	  output += "false";
+ 	else
+ 	  output += "true";
+ 	eat_current();
+ 	_GLIBCPP_DEMANGLER_RETURN;
+       }
+       char c = current();
+       if (c == 'i' || c == 'j' || c == 'l' || c == 'm' || c == 'x' || c == 'y')
+         eat_current();
+       else
+       {
+ 	output += '(';
+ 	if (!decode_type(output))
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	output += ')';
+       }
+       if (!decode_number(output))
+ 	_GLIBCPP_DEMANGLER_FAILURE;
+       if (c == 'j' || c == 'm' || c == 'y')
+         output += 'u';
+       if (c == 'l' || c == 'm')
+         output += 'l';
+       if (c == 'x' || c == 'y')
+         output += "ll";
+     }
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <operator-name> ::= nw				# new           
+ //                 ::= na				# new[]
+ //                 ::= dl				# delete        
+ //                 ::= da				# delete[]      
+ //                 ::= ng				# - (unary)     
+ //                 ::= ad				# & (unary)     
+ //                 ::= de				# * (unary)     
+ //                 ::= co				# ~             
+ //                 ::= pl				# +             
+ //                 ::= mi				# -             
+ //                 ::= ml				# *             
+ //                 ::= dv				# /             
+ //                 ::= rm				# %             
+ //                 ::= an				# &             
+ //                 ::= or				# |             
+ //                 ::= eo				# ^             
+ //                 ::= aS				# =             
+ //                 ::= pL				# +=            
+ //                 ::= mI				# -=            
+ //                 ::= mL				# *=            
+ //                 ::= dV				# /=            
+ //                 ::= rM				# %=            
+ //                 ::= aN				# &=            
+ //                 ::= oR				# |=            
+ //                 ::= eO				# ^=            
+ //                 ::= ls				# <<            
+ //                 ::= rs				# >>            
+ //                 ::= lS				# <<=           
+ //                 ::= rS				# >>=           
+ //                 ::= eq				# ==            
+ //                 ::= ne				# !=            
+ //                 ::= lt				# <             
+ //                 ::= gt				# >             
+ //                 ::= le				# <=            
+ //                 ::= ge				# >=            
+ //                 ::= nt				# !             
+ //                 ::= aa				# &&            
+ //                 ::= oo				# ||            
+ //                 ::= pp				# ++            
+ //                 ::= mm				# --            
+ //                 ::= cm				# ,             
+ //                 ::= pm				# ->*           
+ //                 ::= pt				# ->            
+ //                 ::= cl				# ()            
+ //                 ::= ix				# []            
+ //                 ::= qu				# ?             
+ //                 ::= sz				# sizeof        
+ //                 ::= sr				# scope resolution (::), see below        
+ //                 ::= cv <type>			# (cast)        
+ //                 ::= v <digit> <source-name>		# vendor extended operator
+ //
+ //
+ // Symbol operator codes exist of two characters, we need to find a
+ // quick hash so that their names can be looked up in a table.
+ //
+ // The puzzle :)
+ // Shift the rows so that there is at most one character per column.
+ //
+ // A perfect solution:
+ //                                              horizontal
+ //    .....................................     offset + 'a'
+ // a, ||a||d|||||||||n||||s||||||||||||||||||	    2
+ // c, || || ||lm|o||| |||| ||||||||||||||||||	   -3
+ // d, || a| |e  | ||l |||| |||v||||||||||||||	    3
+ // e, ||  | |   o q|  |||| ||| ||||||||||||||	   -4
+ // g, |e  | |      |  t||| ||| ||||||||||||||	   -3
+ // i, |   | |      |   ||| ||| ||||||||||x|||    12
+ // l, |   | |      e   ||| ||| ||st|||||| |||	    9
+ // m, |   | |          ||| ||| |i  lm|||| |||	   18
+ // n, a   e g          ||t |w| |     |||| |||	    0
+ // o,                  ||  | | |     ||o| r||	   19
+ // p,                  lm  p | t     || |  ||	    6
+ // q,                        |       || u  ||	   14
+ // r,                        |       |m    |s	   20
+ // s,                        r       z     | 	    6
+ //    .....................................
+ // ^            ^__ second character
+ // |___ first character
+ //
+ 
+ // Putting that solution in tables:
+ 
+ char const offset_table_c[1 + CHAR_MAX - CHAR_MIN /* ascii value of first character */ ] = {
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+ #if (CHAR_MIN < 0)
+   // Add -CHAR_MIN extra zeroes (128):
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  
+   //   a    b    c    d    e    f    g    h    i    j    k    l    m    n    o    p    q    r    s    t    u    v
+   0, -95,   0,-100, -94,-101,   0,-100,   0, -85,   0,   0, -88, -79, -97, -78, -91, -83, -77, -91,   0,   0,   0,
+ #else
+   0, 161,   0, 156, 162, 155,   0, 156,   0, 171,   0,   0, 168, 177, 159, 178, 165, 173, 179, 165,   0,   0,   0,
+ #endif
+   // ... more zeros
+ };
+ 
+       struct entry_st 
+       { 
+ 	char const* 	opcode; 
+ 	char const* 	symbol_name; 
+ 	bool 		unary; 
+       };
+ 
+       const entry_st symbol_name_table_c[39] = 
+ 	{
+ 	  { "na",  "operator new[]", true },
+ 	  { "ge",  "operator>=", false },
+ 	  { "aa",  "operator&&", false },
+ 	  { "da",  "operator delete[]", true },
+ 	  { "ne",  "operator!=", false },
+ 	  { "ad",  "operator&", true },	// unary
+ 	  { "ng",  "operator-", true },	// unary
+ 	  { "de",  "operator*", true },	// unary
+ 	  { "cl",  "operator()", true },
+ 	  { "cm",  "operator,", false },
+ 	  { "eo=", "operator^", false },
+ 	  { "co",  "operator~", false },
+ 	  { "eq",  "operator==", false },
+ 	  { "le",  "operator<=", false },
+ 	  { "dl",  "operator delete", true },
+ 	  { "an=", "operator&", false },
+ 	  { "gt",  "operator>", false },
+ 	  { "pl=", "operator+", false },
+ 	  { "pm",  "operator->*", false },
+ 	  { "nt",  "operator!", true },
+ 	  { "as=", "operator", false },
+ 	  { "pp",  "operator++", true },
+ 	  { "nw",  "operator new", true },
+ 	  { "sr",  "::", true },
+ 	  { "dv=", "operator/", false },
+ 	  { "pt",  "operator->", false },
+ 	  { "mi=", "operator-", false },
+ 	  { "ls=", "operator<<", false },
+ 	  { "lt",  "operator<", false },
+ 	  { "ml=", "operator*", false },
+ 	  { "mm",  "operator--", true },
+ 	  { "sz",  "sizeof", true },
+ 	  { "rm=", "operator%", false },
+ 	  { "oo",  "operator||", false },
+ 	  { "qu",  "operator?", false },
+ 	  { "ix",  "operator[]", true },
+ 	  { "or=", "operator|", false },
+ 	  { "", NULL, false },
+ 	  { "rs=", "operator>>", false }
+ 	};
+       
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_operator_name(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_operator_name");
+ 
+     char opcode0 = current();
+     char opcode1 = tolower(next());
+ 
+     register char hash;
+     if ((hash = offset_table_c[opcode0 - CHAR_MIN]))
+     {
+       hash += opcode1;
+       if (
+ #if (CHAR_MIN < 0)
+ 	  hash >= 0 &&
+ #endif
+ 	  hash < 39)
+       {
+ 	int index = static_cast<int>(static_cast<unsigned char>(hash));
+ 	entry_st entry = symbol_name_table_c[index];
+ 	if (entry.opcode[0] == opcode0 && entry.opcode[1] == opcode1 && (opcode1 == current() || entry.opcode[2] == '='))
+ 	{
+ 	  output += entry.symbol_name;
+ 	  if (opcode1 != current())
+ 	    output += '=';
+ 	  eat_current();
+ 	  if (hash == 27 || hash == 28)
+ 	    M_template_args_need_space = true;
+ 	  _GLIBCPP_DEMANGLER_RETURN;
+ 	}
+ 	else if (opcode0 == 'c' && opcode1 == 'v')
+ 	{
+ 	  eat_current();
+ 	  output += "operator ";
+ 	  if (!decode_type(output))
+ 	    _GLIBCPP_DEMANGLER_FAILURE;
+           if (!M_inside_template_args)
+ 	    M_name_is_conversion_operator = true;
+ 	  _GLIBCPP_DEMANGLER_RETURN;
+ 	}
+       }
+     }
+     _GLIBCPP_DEMANGLER_FAILURE;
+   }
+ 
+ //
+ // <expression> ::= <unary operator-name> <expression>
+ //              ::= <binary operator-name> <expression> <expression>
+ //              ::= <expr-primary>
+ //
+ // <expr-primary> ::= <template-param>			# Starts with a T
+ //                ::= L <type> <value number> E		# literal
+ //                ::= L <mangled-name> E			# external name
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_expression(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_expression");
+     if (current() == 'T')
+     {
+       if (!decode_template_param(output))
+         _GLIBCPP_DEMANGLER_FAILURE;
+       _GLIBCPP_DEMANGLER_RETURN;
+     }
+     else if (current() == 'L')
+     {
+       if (!decode_literal(output))
+         _GLIBCPP_DEMANGLER_FAILURE;
+       if (current() != 'E')
+ 	_GLIBCPP_DEMANGLER_FAILURE;
+       eat_current();
+       _GLIBCPP_DEMANGLER_RETURN;
+     }
+     else
+     {
+       char opcode0 = current();
+       char opcode1 = tolower(next());
+ 
+       register char hash;
+       if ((hash = offset_table_c[opcode0 - CHAR_MIN]))
+       {
+ 	hash += opcode1;
+ 	if (
+ #if (CHAR_MIN < 0)
+ 	    hash >= 0 &&
+ #endif
+ 	    hash < 39)
+ 	{
+ 	  int index = static_cast<int>(static_cast<unsigned char>(hash));
+ 	  entry_st entry = symbol_name_table_c[index];
+ 	  if (entry.opcode[0] == opcode0 && entry.opcode[1] == opcode1 && (opcode1 == current() || entry.opcode[2] == '='))
+ 	  {
+ 	    char const* p = entry.symbol_name;
+ 	    if (!strncmp("operator", p, 8))
+ 	      p += 8;
+ 	    if (*p == ' ')
+ 	      ++p;
+ 	    if (entry.unary)
+ 	      output += p;
+ 	    bool is_eq = (opcode1 != current());
+ 	    eat_current();
+ 	    output += '(';
+ 	    if (!decode_expression(output))
+ 	      _GLIBCPP_DEMANGLER_FAILURE;
+ 	    output += ')';
+ 	    if (!entry.unary)
+ 	    {
+ 	      output += ' ';
+ 	      output += p;
+ 	      if (is_eq)
+ 		output += '=';
+ 	      output += ' ';
+ 	      output += '(';
+ 	      if (!decode_expression(output))
+ 		_GLIBCPP_DEMANGLER_FAILURE;
+ 	      output += ')';
+ 	    }
+ 	    _GLIBCPP_DEMANGLER_RETURN;
+ 	  }
+ 	}
+       }
+     }
+     _GLIBCPP_DEMANGLER_FAILURE;
+   }
+ 
+ //
+ // <template-args> ::= I <template-arg>+ E
+ // <template-arg> ::= <type>			        # type or template
+ //                ::= L <type> <value number> E		# literal
+ //                ::= L_Z <encoding> E			# external name
+ //                ::= X <expression> E			# expression
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_template_args(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_template_args");
+     if (eat_current() != 'I')
+       _GLIBCPP_DEMANGLER_FAILURE;
+     int prev_size = M_template_arg_pos.size();
+     ++M_inside_template_args;
+     if (M_template_args_need_space)
+     {
+       output += ' ';
+       M_template_args_need_space = false;
+     }
+     output += '<';
+     for(;;)
+     {
+       if (M_inside_template_args == 1 && !M_inside_type)
+ 	M_template_arg_pos.push_back(M_pos);
+       if (current() == 'X')
+       {
+         eat_current();
+ 	if (!decode_expression(output))
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	if (current() != 'E')
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+         eat_current();
+       }
+       else if (current() == 'L')
+       {
+         if (!decode_literal(output))
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	if (current() != 'E')
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+         eat_current();
+       }
+       else if (!decode_type(output))
+         _GLIBCPP_DEMANGLER_FAILURE;
+       if (current() == 'E')
+         break;
+       output += ", ";
+     }
+     eat_current();
+     if (*(output.rbegin()) == '>')
+       output += ' ';
+     output += '>';
+     --M_inside_template_args;
+     if (!M_inside_template_args && !M_inside_type)
+     {
+       M_name_is_template = true;
+       M_template_arg_pos_offset = prev_size;
+     }
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <bare-function-type> ::= <signature type>+		# types are parameter types
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_bare_function_type(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_bare_function_type");
+     if (M_saw_destructor)
+     {
+       if (eat_current() != 'v' || (current() != 'E' && current() != 0))
+         _GLIBCPP_DEMANGLER_FAILURE;
+       output += "()";
+       M_saw_destructor = false;
+       _GLIBCPP_DEMANGLER_RETURN;
+     }
+     output += '(';
+     M_template_args_need_space = false;
+     if (!decode_type(output))			// Must have at least one parameter
+       _GLIBCPP_DEMANGLER_FAILURE;
+     while (current() != 'E' && current() != 0)
+     {
+       output += ", ";
+       if (!decode_type(output))
+ 	_GLIBCPP_DEMANGLER_FAILURE;
+     }
+     output += ')';
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <type> ::= <builtin-type>				# Starts with a lower case character != r.
+ //        ::= <function-type>				# Starts with F
+ //        ::= <class-enum-type>				# Starts with N, S, C, D, Z, a digit or a lower case character.
+ //							#   since a lower case character would be an operator name, that would
+ //							#   be an error.  The S is a substitution or St (::std::).  A 'C' would
+ //							#   be a constructor and thus also an error.
+ //        ::= <template-param>				# Starts with T
+ //        ::= <substitution>                         	# Starts with S
+ //        ::= <template-template-param> <template-args>	# Starts with T or S, equivalent with the above.
+ //
+ //        ::= <array-type>				# Starts with A
+ //        ::= <pointer-to-member-type>			# Starts with M
+ //        ::= <CV-qualifiers> <type>			# Starts with r, V or K
+ //        ::= P <type>   # pointer-to			# Starts with P
+ //        ::= R <type>   # reference-to			# Starts with R
+ //        ::= C <type>   # complex pair (C 2000)	# Starts with C
+ //        ::= G <type>   # imaginary (C 2000)		# Starts with G
+ //        ::= U <source-name> <type>     		# vendor extended type qualifier, starts with U
+ //
+ // <template-template-param> ::= <template-param>
+ //                           ::= <substitution>
+ 
+ // My own analysis of how to decode qualifiers:
+ //
+ // F is a <function-type>, <T> is a <builtin-type>, <class-enum-type>, <template-param> or <template-template-param> <template-args>.
+ // <Q> represents a series of qualifiers (not G or C).
+ // <C> is an unqualified type.  <R> is a qualified type.
+ // <B> is the bare-function-type without return type.  <I> is the array index.
+ //
+ //							Substitutions:
+ // <Q>M<C><Q2>F<R><B>E	==> R (C::*Q)B Q2		"<C>", "F<R><B>E" (<R> and <B> recursive), "M<C><Q2>F<R><B>E".
+ // <Q>F<R><B>E 		==> R (Q)B			"<R>", "<B>" (<B> recursive) and "F<R><B>E".
+ // <Q>G<T>     		==> imaginary T Q		"<T>", "G<T>" (<T> recursive).
+ // <Q>C<T>     		==> complex T Q			"<T>", "C<T>" (<T> recursive).
+ // <Q><T>      		==> T Q				"<T>" (<T> recursive).
+ //
+ // where Q is any of:
+ //
+ // <Q>P   		==> *Q				"P..."
+ // <Q>R   		==> &Q				"R..."
+ // <Q>[K|V|r]+	==> [ const| volatile| restrict]+Q	"KVr..."
+ // <Q>U<S>		==>  SQ				"U<S>..."
+ // A<I>		==>  [I]				"A<I>..." (<I> recursive).
+ // <Q>A<I>		==>  (Q) [I]			"A<I>..." (<I> recursive).
+ // <Q>M<C>		==> C::*Q			"M<C>..." (<C> recursive).
+ //  
+ // A <substitution> is handled with an input position switch during which new substitutions are
+ // turned off.  Because recursive handling of types (and therefore the order in which substitutions
+ // must be generated) must be done left to right, but the generation of Q needs processing right to left,
+ // substitutions per <type> are generated by reading the input left to right and marking the starts of
+ // all substitutions only - implicitly finishing them at the end of the type.  Then the output and real
+ // substitutions are generated.
+ //
+ // The following comment was for the demangling of g++ version 3.0.x.  The mangling (and I believe
+ // even the ABI description) have been fixed now (as of g++ version 3.1).	
+ //
+ // g++ 3.0.x only:
+ // The ABI specifies for pointer-to-member function types the format <Q>M<T>F<R><B>E.  In other words,
+ // the qualifier <Q2> (see above) is implicitely contained in <T> instead of explicitly part of the M
+ // format.  I am convinced that this is a bug in the ABI.  Unfortunately, this is how we have to
+ // demangle things as it has a direct impact on the order in which substitutions are stored.
+ // This ill-formed design results in rather ill-formed demangler code too however :/
+ //
+ // <Q2> is now explicitely part of the M format.
+ //
+ template<typename Allocator>
+   void qualifier_list<Allocator>::
+   decode_qualifiers(string_type& output)
+   {
+     string_type postfix;
+     for(typename std::vector<qualifier<Allocator>, Allocator>::reverse_iterator iter = M_qualifier_starts.rbegin(); iter != M_qualifier_starts.rend();)
+     {
+       if (!(*iter).part_of_substitution())
+       {
+ 	int saved_inside_substitution = M_demangler.M_inside_substitution;
+         M_demangler.M_inside_substitution = 0;
+ 	M_demangler.add_substitution((*iter).start_pos(), type);
+ 	M_demangler.M_inside_substitution = saved_inside_substitution;
+       }
+       char qualifier_char = (*iter).first_qualifier();
+       for(; qualifier_char; qualifier_char = (*iter).next_qualifier())
+       {
+ 	switch(qualifier_char)
+ 	{
+ 	  case 'P':
+ 	    output += "*";
+ 	    break;
+ 	  case 'R':
+ 	    output += "&";
+ 	    break;
+ 	  case 'K':
+ 	    output += " const";
+ 	    continue;
+ 	  case 'V':
+ 	    output += " volatile";
+ 	    continue;
+ 	  case 'r':
+ 	    output += " restrict";
+ 	    continue;
+ 	  case 'A':
+ 	  {
+ 	    string_type index = (*iter).optional_type();
+ 	    if (++iter != M_qualifier_starts.rend())
+ 	    {
+ 	      output += " (";
+ 	      postfix = ") [" + index + "]" + postfix;
+ 	    }
+ 	    else
+ 	    {
+ 	      output += " [";
+ 	      output += index;
+ 	      output += "]";
+ 	    }
+ 	    break;
+ 	  }
+ 	  case 'M':
+ 	    output += " ";
+ 	    output += (*iter).optional_type();
+ 	    output += "::*";
+ 	    break;
+ 	  case 'U':
+ 	    output += " ";
+ 	    output += (*iter).optional_type();
+ 	    break;
+ 	  case 'G':	// Only here so we added a substitution.
+ 	    break;
+ 	}
+ 	break;
+       }
+       if (qualifier_char != 'A')
+ 	++iter;
+     }
+     output += postfix;
+     M_printing_suppressed = false;
+   }
+ 
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_type(string_type& output, qualifier_list<Allocator>* qualifiers)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING(qualifiers ? "decode_type" : "decode_type[with qualifiers]");
+     ++M_inside_type;
+     bool recursive_template_param_or_substitution_call;
+     if (!(recursive_template_param_or_substitution_call = qualifiers))
+ 	qualifiers = new qualifier_list<Allocator>(*this);
+     // First eat all qualifiers.
+     bool failure = false;
+     for(;;)		// So we can use 'continue' to eat the next qualifier.
+     {
+       int start_pos = M_pos;
+       switch(current())
+       {
+         case 'P':
+ 	  qualifiers->add_qualifier_start(pointer, start_pos, M_inside_substitution);
+ 	  eat_current();
+           continue;
+ 	case 'R':
+ 	  qualifiers->add_qualifier_start(reference, start_pos, M_inside_substitution);
+ 	  eat_current();
+ 	  continue;
+         case 'K':
+ 	case 'V':
+ 	case 'r':
+         {
+ 	  char c;
+ 	  int count = 0;
+ 	  do
+ 	  {
+ 	    ++count;
+ 	    c = next();
+ 	  }
+ 	  while(c == 'K' || c == 'V' || c == 'r');
+ 	  qualifiers->add_qualifier_start(cv_qualifier, start_pos, count, M_inside_substitution);
+ 	  continue;
+ 	}
+ 	case 'U':
+ 	{
+ 	  eat_current();
+ 	  string_type source_name;
+           if (!decode_source_name(source_name))
+ 	  {
+ 	    failure = true;
+ 	    break;
+ 	  }
+           qualifiers->add_qualifier_start(vendor_extension, start_pos, source_name, M_inside_substitution);
+ 	  continue;
+ 	}
+ 	case 'A':
+ 	{
+ 	  // <array-type> ::= A <positive dimension number> _ <element type>
+ 	  //              ::= A [<dimension expression>] _ <element type>
+ 	  //
+ 	  string_type index;
+ 	  int saved_pos;
+ 	  store(saved_pos);
+ 	  if (next() == 'n' || !decode_number(index))
+ 	  {
+ 	    restore(saved_pos);
+ 	    if (next() != '_' && !decode_expression(index))
+ 	    {
+ 	      failure = true;
+ 	      break;
+ 	    }
+ 	  }
+ 	  if (eat_current() != '_')
+ 	  {
+ 	    failure = true;
+ 	    break;
+ 	  }
+           qualifiers->add_qualifier_start(array, start_pos, index, M_inside_substitution);
+ 	  continue;
+ 	}
+ 	case 'M':
+ 	{
+ 	  // <Q>M<C> or <Q>M<C><Q2>F<R><B>E
+ 	  eat_current();
+ 	  string_type class_type;
+ 	  if (!decode_type(class_type))		// <C>
+ 	  {
+ 	    failure = true;
+ 	    break;
+ 	  }
+ 	  if (M_str[start_pos + 1] != 'S' || M_str[start_pos + 2] == 't')
+ 	    add_substitution(start_pos + 1, type);					// substitution: "<C>".
+ 	  char c = current();
+ 	  if (c == 'F' || c == 'K' || c == 'V' || c == 'r')	// Must be CV-qualifiers and a member function pointer.
+ 	  {
+ 	    // <Q>M<C><Q2>F<R><B>E	==> R (C::*Q)B Q2		"<C>", "<C><Q2>", "F<R><B>E" (<R> and <B> recursive), "M<C><Q2>F<R><B>E".
+ 	    int count = 0;
+ 	    int Q2_start_pos = M_pos;
+ 	    while(c == 'K' || c == 'V' || c == 'r')		// Decode <Q2>
+ 	    {
+ 	      ++count;
+ 	      c = next();
+ 	    }
+ 	    qualifier_list<Allocator> class_type_qualifiers(*this);
+ 	    if (count)
+ 	      class_type_qualifiers.add_qualifier_start(cv_qualifier, Q2_start_pos, count, M_inside_substitution);
+ 	    string_type member_function_qualifiers;
+ 	    class_type_qualifiers.decode_qualifiers(member_function_qualifiers);	// substitution: "<C><Q2>".
+ 	    if (eat_current() != 'F')
+ 	    {
+ 	      failure = true;
+ 	      break;
+ 	    }
+ 	    // Return type.
+ 	    // Constructors, destructors and conversion operators don't have a return type, but seem to never get here.
+ 	    if (!decode_type(output))						// substitution: "F<R><B>E" (<R> and <B> recursive).
+ 	    {
+ 	      failure = true;
+ 	      break;
+ 	    }
+ 	    output += " (";
+ 	    output += class_type;
+ 	    output += "::*";
+ 	    string_type bare_function_type;
+ 	    if (!decode_bare_function_type(bare_function_type) || eat_current() != 'E')
+ 	    {
+ 	      failure = true;
+ 	      break;
+ 	    }
+ 	    add_substitution(start_pos, type);					// substitution: "M<C><Q2>F<R><B>E".
+ 	    qualifiers->decode_qualifiers(output);				// substitution: all qualified types if any.
+ 	    output += ")";
+ 	    output += bare_function_type;
+ 	    output += member_function_qualifiers;
+ 	    goto decode_type_exit;
+ 	  }
+           qualifiers->add_qualifier_start(pointer_to_member, start_pos, class_type, M_inside_substitution);
+ 	  continue;
+ 	}
+         default:
+ 	  break;
+       }
+       break;
+     }
+     if (!failure)
+     {
+       // <Q>G<T>     		==> imaginary T Q		"<T>", "G<T>" (<T> recursive).
+       // <Q>C<T>     		==> complex T Q			"<T>", "C<T>" (<T> recursive).
+       if (current() == 'C' || current() == 'G')
+       {
+ 	output += current() == 'C' ? "complex " : "imaginary ";
+ 	qualifiers->add_qualifier_start(complex_or_imaginary, M_pos, M_inside_substitution);
+ 	eat_current();
+       }
+       int start_pos = M_pos;
+       switch(current())
+       {
+ 	case 'F':
+ 	{
+ 	  // <Q>F<R><B>E 		==> R (Q)B			"<R>", "<B>" (<B> recursive) and "F<R><B>E".
+ 	  eat_current();
+ 	  // Return type.
+ 	  if (!decode_type(output))				// substitution: "<R>".
+ 	  {
+ 	    failure = true;
+ 	    break;
+ 	  }
+ 	  output += " (";
+ 	  string_type bare_function_type;
+ 	  if (!decode_bare_function_type(bare_function_type) || eat_current() != 'E')	// substitution: "<B>" (<B> recursive).
+ 	  {
+ 	    failure = true;
+ 	    break;
+ 	  }
+ 	  add_substitution(start_pos, type);			// substitution: "F<R><B>E"
+ 	  qualifiers->decode_qualifiers(output);		// substitution: all qualified types, if any.
+ 	  output += ")";
+ 	  output += bare_function_type;
+ 	  break;
+ 	}
+ 	case 'T':
+ 	  if (!decode_template_param(output, qualifiers))
+ 	  {
+ 	    failure = true;
+ 	    break;
+ 	  }
+ 	  if (current() == 'I')
+ 	  {
+ 	    add_substitution(start_pos, template_template_param);	// substitution: "<template-template-param>".
+ 	    if (!decode_template_args(output))
+ 	    {
+ 	      failure = true;
+ 	      break;
+ 	    }
+ 	  }
+ 	  if (!recursive_template_param_or_substitution_call && qualifiers->suppressed())
+ 	  {
+ 	    add_substitution(start_pos, type);			// substitution: "<template-param>" or "<template-template-param> <template-args>".
+ 	    qualifiers->decode_qualifiers(output);		// substitution: all qualified types, if any.
+ 	  }
+ 	  break;
+ 	case 'S':
+ 	  if (M_pos >= M_maxpos)
+ 	  {
+ 	    failure = true;
+ 	    break;
+ 	  }
+ 	  if (M_str[M_pos + 1] != 't')
+ 	  {
+ 	    if (!decode_substitution(output, qualifiers))
+ 	    {
+ 	      failure = true;
+ 	      break;
+ 	    }
+ 	    if (current() == 'I')
+ 	    {
+ 	      if (!decode_template_args(output))
+ 	      {
+ 		failure = true;
+ 		break;
+ 	      }
+ 	      if (!recursive_template_param_or_substitution_call && qualifiers->suppressed())
+ 		add_substitution(start_pos, type);			// substitution: "<template-template-param> <template-args>".
+ 	    }
+ 	    if (!recursive_template_param_or_substitution_call && qualifiers->suppressed())
+ 	      qualifiers->decode_qualifiers(output);			// substitution: all qualified types, if any.
+ 	    break;
+ 	  }
+ 	  /* Fall-through for St */
+ 	case 'N':
+ 	case 'Z':
+ 	case '0':
+ 	case '1':
+ 	case '2':
+ 	case '3':
+ 	case '4':
+ 	case '5':
+ 	case '6':
+ 	case '7':
+ 	case '8':
+ 	case '9':
+ 	  // <Q><T>      		==> T Q				"<T>" (<T> recursive).
+ 	  if (!decode_class_enum_type(output))
+ 	  {
+ 	    failure = true;
+ 	    break;
+ 	  }
+           if (!recursive_template_param_or_substitution_call)
+ 	  {
+ 	    add_substitution(start_pos, type);				// substitution: "<class-enum-type>".
+ 	    qualifiers->decode_qualifiers(output);			// substitution: all qualified types, if any.
+ 	  }
+           else
+ 	    qualifiers->printing_suppressed();
+ 	  break;
+ 	default:
+ 	  // <Q><T>      		==> T Q				"<T>" (<T> recursive).
+ 	  if (!decode_builtin_type(output))
+ 	  {
+ 	    failure = true;
+ 	    break;
+ 	  }
+ 	  // If decode_type was called from decode_template_param then we need to suppress calling qualifiers here
+ 	  // in order to get a substitution added anyway (for the <template-param>).
+           if (!recursive_template_param_or_substitution_call)
+ 	    qualifiers->decode_qualifiers(output);
+           else
+ 	    qualifiers->printing_suppressed();
+ 	  break;
+       }
+     }
+ decode_type_exit:
+     --M_inside_type;
+     if (!recursive_template_param_or_substitution_call)
+       delete qualifiers;
+     if (failure)
+       _GLIBCPP_DEMANGLER_FAILURE;
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+ //               ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+ //
+ // <prefix> ::= <prefix> <unqualified-name>
+ //          ::= <template-prefix> <template-args>
+ //          ::= # empty
+ //          ::= <substitution>
+ //
+ // <template-prefix> ::= <prefix> <template unqualified-name>
+ //                   ::= <substitution>
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_nested_name(string_type& output,
+                      string_type& qualifiers)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_nested_name");
+ 
+     if (current() != 'N' || M_pos >= M_maxpos)
+       _GLIBCPP_DEMANGLER_FAILURE;
+ 
+     // <CV-qualifiers> ::= [r] [V] [K]       # restrict (C99), volatile, const
+     char const* qualifiers_start = &M_str[M_pos + 1];
+     for (char c = next(); c == 'K' || c == 'V' || c == 'r'; c = next());
+     for (char const* qualifier_ptr = &M_str[M_pos - 1]; qualifier_ptr >= qualifiers_start; --qualifier_ptr)
+       switch(*qualifier_ptr)
+       {
+         case 'K':
+ 	  qualifiers += " const";
+ 	  break;
+ 	case 'V':
+ 	  qualifiers += " volatile";
+ 	  break;
+ 	case 'r':
+ 	  qualifiers += " restrict";
+ 	  break;
+       }
+ 
+     int number_of_prefixes = 0;
+     int substitution_start = M_pos;
+     for(;;)
+     {
+       ++number_of_prefixes;
+       if (current() == 'S')
+       {
+         if (!decode_substitution(output))
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+       }
+       else if (current() == 'I')
+       {
+ 	if (!decode_template_args(output))
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	if (current() != 'E')
+ 	  add_substitution(substitution_start, nested_name_prefix, number_of_prefixes);
+ 	  								// substitution: "<template-prefix> <template-args>".
+       }
+       else
+       {
+         if (!decode_unqualified_name(output))
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	if (current() != 'E')
+ 	  add_substitution(substitution_start, (current() == 'I') ? nested_name_template_prefix : nested_name_prefix, number_of_prefixes);
+ 	  								// substitution: "<prefix> <unqualified-name>" or
+ 									// "<prefix> <template unqualified-name>".
+       }
+       if (current() == 'E')
+       {
+         eat_current();
+         _GLIBCPP_DEMANGLER_RETURN;
+       }
+       if (current() != 'I')
+ 	output += "::";
+       else if (M_template_args_need_space)
+         output += ' ';
+       M_template_args_need_space = false;
+     }
+     _GLIBCPP_DEMANGLER_FAILURE;
+   }
+ 
+ // <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+ //              := Z <function encoding> E s [<discriminator>]
+ // <discriminator> := _ <non-negative number>
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_local_name(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_local_name");
+     if (current() != 'Z' || M_pos >= M_maxpos)
+       _GLIBCPP_DEMANGLER_FAILURE;
+     if ((M_pos += decode_encoding(output, M_str + M_pos + 1, M_maxpos - M_pos) + 1) < 0 || eat_current() != 'E')
+       _GLIBCPP_DEMANGLER_FAILURE;
+     output += "::";
+     if (current() == 's')
+     {
+       eat_current();
+       output += "string literal";
+     }
+     else
+     {
+       string_type nested_name_qualifiers;
+       if (!decode_name(output, nested_name_qualifiers))
+ 	_GLIBCPP_DEMANGLER_FAILURE;
+       output += nested_name_qualifiers;
+     }
+     string_type discriminator;
+     if (current() == '_' && next() != 'n' && !decode_number(discriminator))
+       _GLIBCPP_DEMANGLER_FAILURE;
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <source-name> ::= <positive length number> <identifier>
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_source_name(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_source_name");
+     int length = current() - '0';
+     if (length < 1 || length > 9)
+       _GLIBCPP_DEMANGLER_FAILURE;
+     while(std::isdigit(next()))
+       length = 10 * length + current() - '0';
+     char const* ptr = &M_str[M_pos];
+     if (length > 11 && !strncmp(ptr, "_GLOBAL_", 8) && ptr[9] == 'N' && ptr[8] == ptr[10])
+     {
+       output += "(anonymous namespace)";
+       if ((M_pos += length) > M_maxpos + 1)
+ 	_GLIBCPP_DEMANGLER_FAILURE;
+     }
+     else
+       while(length--)
+       {
+ 	if (current() == 0)
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	output += eat_current();
+       }
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <unqualified-name> ::= <operator-name>				# Starts with lower case
+ //                    ::= <ctor-dtor-name>  				# Starts with 'C' or 'D'
+ //                    ::= <source-name>   				# Starts with a digit
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_unqualified_name(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_unqualified_name");
+     if (std::isdigit(current()))
+     {
+       if (!M_inside_template_args)
+       {
+ 	M_function_name.clear();
+ 	M_name_is_template = false;
+ 	M_name_is_cdtor = false;
+ 	M_name_is_conversion_operator = false;
+ 	if (!decode_source_name(M_function_name))
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	output += M_function_name;
+       }
+       else if (!decode_source_name(output))
+         _GLIBCPP_DEMANGLER_FAILURE;
+       _GLIBCPP_DEMANGLER_RETURN;
+     }
+     if (islower(current()))
+     {
+       if (!M_inside_template_args)
+       {
+ 	M_function_name.clear();
+ 	M_name_is_template = false;
+ 	M_name_is_cdtor = false;
+ 	M_name_is_conversion_operator = false;
+         if (!decode_operator_name(M_function_name))
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	output += M_function_name;
+       }
+       _GLIBCPP_DEMANGLER_RETURN;
+     }
+     if (current() == 'C' || current() == 'D')
+     {
+       if (M_inside_template_args)
+         _GLIBCPP_DEMANGLER_FAILURE;
+       // <ctor-dtor-name> ::= C1				# complete object (in-charge) constructor
+       //                  ::= C2				# base object (not-in-charge) constructor
+       //                  ::= C3				# complete object (in-charge) allocating constructor
+       //                  ::= D0				# deleting (in-charge) destructor
+       //                  ::= D1				# complete object (in-charge) destructor
+       //                  ::= D2				# base object (not-in-charge) destructor
+       //
+       if (current() == 'C')
+       {
+ 	char c = next();
+ 	if (c < '1' || c > '3')
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+       }
+       else
+       {
+ 	char c = next();
+ 	if (c < '0' || c > '2')
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	output += '~';
+ 	M_saw_destructor = true;
+       }
+       M_name_is_cdtor = true;
+       eat_current();
+       output += M_function_name;
+       _GLIBCPP_DEMANGLER_RETURN;
+     }
+     _GLIBCPP_DEMANGLER_FAILURE;
+   }
+ 
+ // <unscoped-name> ::= <unqualified-name>		# Starts not with an 'S'
+ //                 ::= St <unqualified-name>		# ::std::
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_unscoped_name(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_unscoped_name");
+     if (current() == 'S')
+     {
+       if (next() != 't')
+         _GLIBCPP_DEMANGLER_FAILURE;
+       eat_current();
+       output += "std::";
+     }
+     decode_unqualified_name(output);
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+ // <name> ::= <nested-name>						# Starts with 'N'
+ //        ::= <unscoped-name>						# Starts with 'S', 'C', 'D', a digit or a lower case character.
+ //        ::= <unscoped-template-name> <template-args>		# idem
+ //        ::= <local-name>						# Starts with 'Z'
+ //
+ // <unscoped-template-name> ::= <unscoped-name>
+ //                          ::= <substitution>
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_name(string_type& output,
+               string_type& nested_name_qualifiers)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_name");
+     int substitution_start = M_pos;
+     if (current() == 'S' && (M_pos >= M_maxpos || M_str[M_pos + 1] != 't'))
+     {
+       if (!decode_substitution(output))
+         _GLIBCPP_DEMANGLER_FAILURE;
+     }
+     else if (current() == 'N')
+     {
+       decode_nested_name(output, nested_name_qualifiers);
+       _GLIBCPP_DEMANGLER_RETURN;
+     }
+     else if (current() == 'Z')
+     {
+       decode_local_name(output);
+       _GLIBCPP_DEMANGLER_RETURN;
+     }
+     else if (!decode_unscoped_name(output))
+       _GLIBCPP_DEMANGLER_FAILURE;
+     if (current() == 'I')
+     {
+       // Must have been an <unscoped-template-name>.
+       add_substitution(substitution_start, unscoped_template_name);
+       if (!decode_template_args(output))
+ 	_GLIBCPP_DEMANGLER_FAILURE;
+     }
+     M_template_args_need_space = false;
+     _GLIBCPP_DEMANGLER_RETURN;
+   }
+ 
+       // <call-offset> ::= h <nv-offset> _
+       //               ::= v <v-offset> _
+       // <nv-offset>   ::= <offset number> 
+       // non-virtual base override
+ 
+       // <v-offset>    ::= <offset number> _ <virtual offset number>
+       // virtual base override, with vcall offset
+ 
+       template<typename Allocator>
+         bool 
+         session<Allocator>::decode_call_offset(string_type&)
+         {
+ 	  _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_call_offset");
+ 	  if (current() == 'h')
+ 	    {
+ 	      string_type dummy;
+ 	      eat_current();
+ 	      if (decode_number(dummy) && current() == '_')
+ 		{
+ 		  eat_current();
+ 		  _GLIBCPP_DEMANGLER_RETURN;
+ 		}
+ 	    }
+ 	  else if (current() == 'v')
+ 	    {
+ 	      string_type dummy;
+ 	      eat_current();
+ 	      if (decode_number(dummy) && current() == '_')
+ 		{
+ 		  eat_current();
+ 		  if (decode_number(dummy) && current() == '_')
+ 		    {
+ 		      eat_current();
+ 		      _GLIBCPP_DEMANGLER_RETURN;
+ 		    }
+ 		}
+ 	    }
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	}
+       
+ //
+ // <special-name> ::= TV <type>				# virtual table
+ //                ::= TT <type>				# VTT structure (construction vtable index)
+ //                ::= TI <type>				# typeinfo structure
+ //                ::= TS <type>				# typeinfo name (null-terminated byte string)
+ //                ::= GV <object name>			# Guard variable for one-time initialization of static objects in a local scope
+ //                ::= T <call-offset> <base encoding>		# base is the nominal target function of thunk
+ //                ::= Tc <call-offset> <call-offset> <base encoding> # base is the nominal target function of thunk
+ //								# first call-offset is 'this' adjustment
+ //								# second call-offset is result adjustment
+ //
+ template<typename Allocator>
+   bool session<Allocator>::
+   decode_special_name(string_type& output)
+   {
+     _GLIBCPP_DEMANGLER_DOUT_ENTERING("decode_special_name");
+     if (current() == 'G')
+     {
+       if (next() != 'V')
+         _GLIBCPP_DEMANGLER_FAILURE;
+       output += "guard variable for ";
+       string_type nested_name_qualifiers;
+       eat_current();
+       if (!decode_name(output, nested_name_qualifiers))
+         _GLIBCPP_DEMANGLER_FAILURE;
+       output += nested_name_qualifiers;
+       _GLIBCPP_DEMANGLER_RETURN;
+     }
+     else if (current() != 'T')
+       _GLIBCPP_DEMANGLER_FAILURE;
+     switch(next())
+     {
+       case 'V':
+         output += "vtable for ";
+ 	eat_current();
+ 	decode_type(output);
+         _GLIBCPP_DEMANGLER_RETURN;
+       case 'T':
+         output += "VTT for ";
+ 	eat_current();
+ 	decode_type(output);
+         _GLIBCPP_DEMANGLER_RETURN;
+       case 'I':
+         output += "typeinfo for ";
+ 	eat_current();
+ 	decode_type(output);
+         _GLIBCPP_DEMANGLER_RETURN;
+       case 'S':
+         output += "typeinfo name for ";
+ 	eat_current();
+ 	decode_type(output);
+         _GLIBCPP_DEMANGLER_RETURN;
+       case 'c':
+         output += "covariant return thunk to ";
+ 	if (!decode_call_offset(output)
+ 	    || !decode_call_offset(output)
+ 	    || (M_pos += decode_encoding(output, M_str + M_pos, M_maxpos - M_pos + 1)) < 0)
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+         _GLIBCPP_DEMANGLER_RETURN;
+       case 'C':		// GNU extension?
+       {
+         string_type first;
+         output += "construction vtable for ";
+ 	eat_current();
+ 	if (!decode_type(first))
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+         while(std::isdigit(current()))
+ 	  eat_current();
+ 	if (eat_current() != '_')
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	if (!decode_type(output))
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+ 	output += "-in-";
+ 	output += first;
+         _GLIBCPP_DEMANGLER_RETURN;
+       }
+       default:
+         if (current() == 'v')
+ 	  output += "virtual thunk to ";
+ 	else
+ 	  output += "non-virtual thunk to ";
+ 	if (!decode_call_offset(output) || (M_pos += decode_encoding(output, M_str + M_pos, M_maxpos - M_pos + 1)) < 0)
+ 	  _GLIBCPP_DEMANGLER_FAILURE;
+         _GLIBCPP_DEMANGLER_RETURN;
+     }
+   }
+ 
+ 
+       // <encoding> ::= <function name> <bare-function-type>
+       // Starts with 'C', 'D', 'N', 'S', a digit or a lower case character.
+ 
+       //            ::= <data name>
+       // idem
+ 
+       //            ::= <special-name>
+       // Starts with 'T' or 'G'.
+       template<typename Allocator>
+         int 
+         session<Allocator>::decode_encoding(string_type& output, 
+ 					    char const* in, int len)
+       {
+ #ifdef CWDEBUG
+ 	_GLIBCPP_DEMANGLER_DOUT(dc::demangler, "Output thus far: \"" << output << '"');
+ 	string_type input(in, len > 0x40000000 ? strlen(in) : len);
+ 	_GLIBCPP_DEMANGLER_DOUT(dc::demangler, "Entering decode_encoding(\"" << input << "\")");
+ #endif
+ 	if (len <= 0)
+ 	  return INT_MIN;
+ 	session<Allocator> demangler_session(in, len);
+ 	string_type nested_name_qualifiers;
+ 	int saved_pos;
+ 	demangler_session.store(saved_pos);
+ 	if (demangler_session.decode_special_name(output))
+ 	  return demangler_session.M_pos;
+ 	demangler_session.restore(saved_pos);
+ 	string_type name;
+ 	if (!demangler_session.decode_name(name, nested_name_qualifiers))
+ 	  return INT_MIN;
+ 	if (demangler_session.current() == 0 || demangler_session.current() == 'E')
+ 	  {
+ 	    output += name;
+ 	    output += nested_name_qualifiers;
+ 	    return demangler_session.M_pos;
+ 	  }
+ 	// Must have been a <function name>.
+ 	if (demangler_session.M_name_is_template 
+ 	    && !(demangler_session.M_name_is_cdtor || demangler_session.M_name_is_conversion_operator))
+ 	  {
+ 	    if (!demangler_session.decode_type(output))	// Return type of function
+ 	      return INT_MIN;
+ 	    output += ' ';
+ 	  }
+ 	output += name;
+ 	if (!demangler_session.decode_bare_function_type(output))
+ 	  return INT_MIN;
+ 	output += nested_name_qualifiers;
+ 	return demangler_session.M_pos;
+       }
+   } // namespace demangler
+   
+ 
+   // Public interface
+   template<typename Allocator>
+     struct demangle 
+     {
+       typedef Allocator allocator_type;
+       typedef std::basic_string<char, std::char_traits<char>, Allocator> 
+           string_type;
+       static string_type symbol(char const* in);
+       static string_type type(char const* in);
+     };
+ 
+   // demangle::symbol()
+   // Demangle `input' which should be a mangled function name as for
+   // instance returned by nm(1).
+   template<typename Allocator>
+     std::basic_string<char, std::char_traits<char>, Allocator> 
+     demangle<Allocator>::symbol(char const* input)
+     {
+       // <mangled-name> ::= _Z <encoding>
+       // <mangled-name> ::= _GLOBAL_ _<type>_ _Z <encoding>		
+       //                    <type> can be I or D (GNU extension)
+       typedef demangler::session<Allocator> demangler_type;
+       string_type result;
+       bool failure = (input[0] != '_');
+       
+       if (!failure)
+ 	{
+ 	  if (input[1] == 'G')
+ 	    {
+ 	      if (!strncmp(input, "_GLOBAL__", 9) 
+ 		  && (input[9] == 'D' || input[9] == 'I')
+ 		  && input[10] == '_' && input[11] == '_' && input[12] == 'Z')
+ 		{
+ 		  if (input[9] == 'D')
+ 		    result.assign("global destructors keyed to ", 28);
+ 		  else
+ 		    result.assign("global constructors keyed to ", 29);
+ 		  int cnt = demangler_type::decode_encoding(result, input + 13,
+ 							    INT_MAX);
+ 		  if (cnt < 0 || input[cnt + 13] != 0)
+ 		    failure = true;
+ 		}
+ 	      else
+ 		failure = true;
+ 	    }
+ 	  else if (input[1] == 'Z')
+ 	    {
+ 	      int cnt = demangler_type::decode_encoding(result, input + 2, 
+ 							INT_MAX);
+ 	      if (cnt < 0 || input[cnt + 2] != 0)
+ 		failure = true;
+ 	    }
+ 	  else
+ 	    failure = true;
+ 	}
+       
+       // Failure to demangle, return the mangled name.
+       if (failure)
+ 	result.assign(input, strlen(input));		
+       
+       return result;
+     }
+   
+   // demangle::type()
+   // Demangle `input' which must be a zero terminated mangled type
+   // name as for instance returned by std::type_info::name().
+   template<typename Allocator>
+     std::basic_string<char, std::char_traits<char>, Allocator> 
+     demangle<Allocator>::type(char const* input)
+     {
+       std::basic_string<char, std::char_traits<char>, Allocator> result;
+       if (input == NULL)
+ 	result = "(null)";
+       else
+ 	{
+ 	  demangler::session<Allocator> demangler_session(input, INT_MAX);
+ 	  if (!demangler_session.decode_type(result) 
+ 	      || demangler_session.remaining_input_characters())
+ 	    {
+ 	      // Failure to demangle, return the mangled name.
+ 	      result = input;				
+ 	    }
+ 	}
+       return result;
+     }
+ } // namespace __gnu_cxx
+ 
+ #endif // __DEMANGLE_H
+ 
Index: config/linker-map.gnu
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/config/linker-map.gnu,v
retrieving revision 1.25
diff -c -p -r1.25 linker-map.gnu
*** config/linker-map.gnu	26 Nov 2002 01:37:49 -0000	1.25
--- config/linker-map.gnu	23 Dec 2002 16:51:28 -0000
*************** GLIBCPP_3.2 {
*** 57,63 ****
        std::locale::_S_num_categories;
        std::locale::_S_normalize_category*;
        std::locale::_[T-Za-z]*;
!       std::[A-Zm-z]*;
        std::__throw_*;
        std::__basic_file*;
        std::__num_base*;
--- 57,65 ----
        std::locale::_S_num_categories;
        std::locale::_S_normalize_category*;
        std::locale::_[T-Za-z]*;
!       std::[A-Zm-u]*;
!       std::valarray*;
!       std::[A-Zw-z]*;
        std::__throw_*;
        std::__basic_file*;
        std::__num_base*;
*************** GLIBCPP_3.2 {
*** 90,96 ****
      _ZNSbIwSt11char_traitsIwESaIwEE13_S_copy_chars*;
      _ZNSbIwSt11char_traitsIwESaIwEE12_S_constructE[jm]wRKS1_;
      _ZNSbIwSt11char_traitsIwESaIwEE12_S_empty_repEv;
!     _ZSt24__uninitialized_copy_auxIN9*;
      _ZSt26__uninitialized_fill_n_aux*;
      _ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_EPKS3_RKS6_;
      _ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ES3_RKS6_;
--- 92,100 ----
      _ZNSbIwSt11char_traitsIwESaIwEE13_S_copy_chars*;
      _ZNSbIwSt11char_traitsIwESaIwEE12_S_constructE[jm]wRKS1_;
      _ZNSbIwSt11char_traitsIwESaIwEE12_S_empty_repEv;
!     _ZSt24__uninitialized_copy_auxIN9__gnu_cxx17__normal_iterator[0-9]*;
!     _ZSt24__uninitialized_copy_auxIN9__gnu_cxx17__normal_iterator[A-Ha-z]*;
!     _ZSt24__uninitialized_copy_auxIN9__gnu_cxx17__normal_iterator[J-Za-z]*;
      _ZSt26__uninitialized_fill_n_aux*;
      _ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_EPKS3_RKS6_;
      _ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ES3_RKS6_;
*************** CXXABI_1.2 {
*** 253,276 ****
      __cxa_call_unexpected;
      __cxa_current_exception_type;
      __cxa_demangle;
-     __cxa_dyn_string_append_char;
-     __cxa_dyn_string_append_cstr;
-     __cxa_dyn_string_append;
-     __cxa_dyn_string_clear;
-     __cxa_dyn_string_copy_cstr;
-     __cxa_dyn_string_copy;
-     __cxa_dyn_string_delete;
-     __cxa_dyn_string_eq;
-     __cxa_dyn_string_init;
-     __cxa_dyn_string_insert_char;
-     __cxa_dyn_string_insert_cstr;
-     __cxa_dyn_string_insert;
-     __cxa_dyn_string_new;
-     __cxa_dyn_string_prepend_cstr;
-     __cxa_dyn_string_prepend;
-     __cxa_dyn_string_release;
-     __cxa_dyn_string_resize;
-     __cxa_dyn_string_substring;
      __cxa_end_catch;
      __cxa_free_exception;
      __cxa_get_globals;
--- 257,262 ----
*************** CXXABI_1.2 {
*** 294,299 ****
--- 280,305 ----
  
      # __gnu_cxx::_verbose_terminate_handler()
      _ZN9__gnu_cxx27__verbose_terminate_handlerEv;
+ 
+     # XXX Should be removed.
+     __cxa_dyn_string_append_char;
+     __cxa_dyn_string_append_cstr;
+     __cxa_dyn_string_append;
+     __cxa_dyn_string_clear;
+     __cxa_dyn_string_copy_cstr;
+     __cxa_dyn_string_copy;
+     __cxa_dyn_string_delete;
+     __cxa_dyn_string_eq;
+     __cxa_dyn_string_init;
+     __cxa_dyn_string_insert_char;
+     __cxa_dyn_string_insert_cstr;
+     __cxa_dyn_string_insert;
+     __cxa_dyn_string_new;
+     __cxa_dyn_string_prepend_cstr;
+     __cxa_dyn_string_prepend;
+     __cxa_dyn_string_release;
+     __cxa_dyn_string_resize;
+     __cxa_dyn_string_substring;
  
    local:
      *;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]