[RFA,3/3] Move logic out of symbol_find_demangled_name

Message ID 1465051760-25840-4-git-send-email-tom@tromey.com
State New, archived
Headers

Commit Message

Tom Tromey June 4, 2016, 2:49 p.m. UTC
  This patch moves most of the demangling logic out of
symbol_find_demangled_name into the various language_defn objects.

The simplest way to do this seemed to be to add a new method to
language_defn.  This is shame given the existing la_demangle, but
given Ada's unusual needs, and the differing demangling options
between languages, la_demangle didn't seem to fit.

In order to make this work, I made enum language order-sensitive.
This helps preserve the current ordering of demangling operations.

I'm not especially fond of the new name, "la_demangle_for_symbol".

2016-06-04  Tom Tromey  <tom@tromey.com>

	* symtab.c (symbol_find_demangled_name): Loop over languages and
	use language_demangle_for_symbol.
	* rust-lang.c (exp_descriptor_rust): New function.
	(rust_language_defn): Update.
	* p-lang.c (pascal_language_defn): Update.
	* opencl-lang.c (opencl_language_defn): Update.
	* objc-lang.c (objc_demangle_for_symbol): New function.
	(objc_language_defn): Update.
	* m2-lang.c (m2_language_defn): Update.
	* language.h (struct language_defn) <la_demangle_for_symbol>: New
	field.
	(language_demangle_for_symbol): Declare.
	* language.c (language_demangle_for_symbol): New function.
	(unknown_language_defn, auto_language_defn, local_language_defn):
	Update.
	* jv-lang.c (java_demangle_for_symbol): New function.
	(java_language_defn): Use it.
	* go-lang.c (go_demangle_for_symbol): New function.
	(go_language_defn): Use it.
	* f-lang.c (f_language_defn): Update.
	* defs.h (enum language): Reorder.
	* d-lang.c (d_demangle_for_symbol): New function.
	(d_language_defn): Use it.
	* cp-support.h (gdb_demangle_for_symbol): Declare.
	* cp-support.c (gdb_demangle_for_symbol): New function.
	* c-lang.c (c_language_defn, cplus_language_defn)
	(asm_language_defn, minimal_language_defn): Update.
	* ada-lang.c (ada_demangle_for_symbol): New function.
	(ada_language_defn): Use it.
---
 gdb/ChangeLog     |  32 ++++++++++++++++
 gdb/ada-lang.c    |  38 +++++++++++++++++++
 gdb/c-lang.c      |   4 ++
 gdb/cp-support.c  |   8 ++++
 gdb/cp-support.h  |   4 ++
 gdb/d-lang.c      |   9 +++++
 gdb/defs.h        |  11 ++++--
 gdb/f-lang.c      |   7 ++++
 gdb/go-lang.c     |   9 +++++
 gdb/jv-lang.c     |   9 +++++
 gdb/language.c    |  18 +++++++++
 gdb/language.h    |  20 ++++++++++
 gdb/m2-lang.c     |   1 +
 gdb/objc-lang.c   |   9 +++++
 gdb/opencl-lang.c |   1 +
 gdb/p-lang.c      |   1 +
 gdb/rust-lang.c   |  12 ++++++
 gdb/symtab.c      | 107 +++++++-----------------------------------------------
 18 files changed, 203 insertions(+), 97 deletions(-)
  

Comments

Yao Qi June 6, 2016, 2:14 p.m. UTC | #1
Tom Tromey <tom@tromey.com> writes:

> I'm not especially fond of the new name, "la_demangle_for_symbol".
>

How about "la_sniff_by_symbol"?  IMO, symbol_find_demangled_name does
two things, set the language of symbol, and get the demangled name.
It is quite similar to frame unwinder sniffer and frame unwinding.

> --- a/gdb/language.h
> +++ b/gdb/language.h
> @@ -292,6 +292,19 @@ struct language_defn
>      /* Return demangled language symbol, or NULL.  */
>      char *(*la_demangle) (const char *mangled, int options);
>  
> +    /* Demangle a symbol according to this language's rules.  Unlike
> +       la_demangle, this does not take any options.  The return value
> +       should either be NULL if the name cannot be demangled, or an
> +       xmalloc'd string, to be owned by the caller.
> +
> +       If this function returns non-NULL, then it can be assumed that
> +       MANGLED represents a mangled symbol for this language.  If this
> +       function returns NULL, then normally the converse is true, but
> +       RECOGNIZED can be set to 1 to override this.
> +       
> +       RECOGNIZED must be initialized to 0 by the caller.  */
> +    char *(*la_demangle_for_symbol) (const char *mangled, int *recognized);

Why don't we return int to indicate the name can be demangled or not and
put the demangled name in the second parameter if it can be?
  
Pedro Alves June 7, 2016, 2:03 p.m. UTC | #2
On 06/06/2016 03:14 PM, Yao Qi wrote:
> Tom Tromey <tom@tromey.com> writes:
> 
>> > I'm not especially fond of the new name, "la_demangle_for_symbol".
>> >
> How about "la_sniff_by_symbol"?  IMO, symbol_find_demangled_name does
> two things, set the language of symbol, and get the demangled name.
> It is quite similar to frame unwinder sniffer and frame unwinding.
> 

I have to admit that it took me a bit to understand what the "by" meant,
but I think it intends to convey:

  "sniff the symbol's language from the symbol's mangled name".

So s/by symbol/from symbol/ would be better, IMHO.

symbol_find_demangled_name says:

/* (...) attempt to find any demangling algorithm that works and
   then set the language appropriately.  The returned name is allocated
   by the demangler and should be xfree'd.  */

So IMHO, something like "la_sniff_from_mangled_name" would be
even clearer.

BTW, what do we do with the resulting demangled name?  Is
there some sort of guideline for options to pass to the demangler?
Some sort of output that we're aiming for?

Thanks,
Pedro Alves
  
Tom Tromey June 8, 2016, 2:14 a.m. UTC | #3
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

Pedro> So IMHO, something like "la_sniff_from_mangled_name" would be
Pedro> even clearer.

I made this change.

Pedro> BTW, what do we do with the resulting demangled name?  Is
Pedro> there some sort of guideline for options to pass to the demangler?
Pedro> Some sort of output that we're aiming for?

The resulting name, if any, is put into a symbol by symbol_set_names.
(I didn't change this area, just made it so the existing code could be
factored into per-language methods.)

So, it should be whatever is appropriate for a symbol.

I think this area is still a bit messy.  IIRC there are some weird
demangling differences between psymbols and full symbols, and there is
still a hack for Java in symbol_set_names.

Tom
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b58ccde..264355a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,37 @@ 
 2016-06-04  Tom Tromey  <tom@tromey.com>
 
+	* symtab.c (symbol_find_demangled_name): Loop over languages and
+	use language_demangle_for_symbol.
+	* rust-lang.c (exp_descriptor_rust): New function.
+	(rust_language_defn): Update.
+	* p-lang.c (pascal_language_defn): Update.
+	* opencl-lang.c (opencl_language_defn): Update.
+	* objc-lang.c (objc_demangle_for_symbol): New function.
+	(objc_language_defn): Update.
+	* m2-lang.c (m2_language_defn): Update.
+	* language.h (struct language_defn) <la_demangle_for_symbol>: New
+	field.
+	(language_demangle_for_symbol): Declare.
+	* language.c (language_demangle_for_symbol): New function.
+	(unknown_language_defn, auto_language_defn, local_language_defn):
+	Update.
+	* jv-lang.c (java_demangle_for_symbol): New function.
+	(java_language_defn): Use it.
+	* go-lang.c (go_demangle_for_symbol): New function.
+	(go_language_defn): Use it.
+	* f-lang.c (f_language_defn): Update.
+	* defs.h (enum language): Reorder.
+	* d-lang.c (d_demangle_for_symbol): New function.
+	(d_language_defn): Use it.
+	* cp-support.h (gdb_demangle_for_symbol): Declare.
+	* cp-support.c (gdb_demangle_for_symbol): New function.
+	* c-lang.c (c_language_defn, cplus_language_defn)
+	(asm_language_defn, minimal_language_defn): Update.
+	* ada-lang.c (ada_demangle_for_symbol): New function.
+	(ada_language_defn): Use it.
+
+2016-06-04  Tom Tromey  <tom@tromey.com>
+
 	* ada-lang.c (ada_extensions): New array.
 	(ada_language_defn): Use it.
 	* c-lang.c (c_extensions): New array.
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index e3f236f..62a7050 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -1452,6 +1452,43 @@  ada_la_decode (const char *encoded, int options)
   return xstrdup (ada_decode (encoded));
 }
 
+/* Implement la_demangle_for_symbol for Ada.  */
+
+static char *
+ada_demangle_for_symbol (const char *mangled, int *recognized)
+{
+  const char *demangled = ada_decode (mangled);
+
+  if (demangled != mangled && demangled != NULL && demangled[0] != '<')
+    {
+      /* Set the gsymbol language to Ada, but still return NULL.
+	 Two reasons for that:
+
+	 1. For Ada, we prefer computing the symbol's decoded name
+	 on the fly rather than pre-compute it, in order to save
+	 memory (Ada projects are typically very large).
+
+	 2. There are some areas in the definition of the GNAT
+	 encoding where, with a bit of bad luck, we might be able
+	 to decode a non-Ada symbol, generating an incorrect
+	 demangled name (Eg: names ending with "TB" for instance
+	 are identified as task bodies and so stripped from
+	 the decoded name returned).
+
+	 Returning NULL, here, helps us get a little bit of
+	 the best of both worlds.  Because we're last, we should
+	 not affect any of the other languages that were able to
+	 demangle the symbol before us; we get to correctly tag
+	 Ada symbols as such; and even if we incorrectly tagged
+	 a non-Ada symbol, which should be rare, any routing
+	 through the Ada language should be transparent (Ada
+	 tries to behave much like C/C++ with non-Ada symbols).  */
+      *recognized = 1;
+    }
+
+  return NULL;
+}
+
 /* Returns non-zero iff SYM_NAME matches NAME, ignoring any trailing
    suffixes that encode debugging information or leading _ada_ on
    SYM_NAME (see is_name_suffix commentary for the debugging
@@ -14077,6 +14114,7 @@  const struct language_defn ada_language_defn = {
   ada_lookup_symbol_nonlocal,   /* Looking up non-local symbols.  */
   basic_lookup_transparent_type,        /* lookup_transparent_type */
   ada_la_decode,                /* Language specific symbol demangler */
+  ada_demangle_for_symbol,
   NULL,                         /* Language specific
 				   class_name_from_physname */
   ada_op_print_tab,             /* expression operators for printing */
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 9ccb87f..a733754 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -856,6 +856,7 @@  const struct language_defn c_language_defn =
   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   NULL,				/* Language specific symbol demangler */
+  NULL,
   NULL,				/* Language specific
 				   class_name_from_physname */
   c_op_print_tab,		/* expression operators for printing */
@@ -989,6 +990,7 @@  const struct language_defn cplus_language_defn =
   cp_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   cp_lookup_transparent_type,   /* lookup_transparent_type */
   gdb_demangle,			/* Language specific symbol demangler */
+  gdb_demangle_for_symbol,
   cp_class_name_from_physname,  /* Language specific
 				   class_name_from_physname */
   c_op_print_tab,		/* expression operators for printing */
@@ -1040,6 +1042,7 @@  const struct language_defn asm_language_defn =
   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   NULL,				/* Language specific symbol demangler */
+  NULL,
   NULL,				/* Language specific
 				   class_name_from_physname */
   c_op_print_tab,		/* expression operators for printing */
@@ -1091,6 +1094,7 @@  const struct language_defn minimal_language_defn =
   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   NULL,				/* Language specific symbol demangler */
+  NULL,
   NULL,				/* Language specific
 				   class_name_from_physname */
   c_op_print_tab,		/* expression operators for printing */
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index 5662f86..c799216 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -1627,6 +1627,14 @@  gdb_demangle (const char *name, int options)
   return result;
 }
 
+/* See cp-support.h.  */
+
+char *
+gdb_demangle_for_symbol (const char *mangled, int *recognized)
+{
+  return gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
+}
+
 /* Don't allow just "maintenance cplus".  */
 
 static  void
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index 78749c8..7c675d7 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -158,4 +158,8 @@  extern struct cmd_list_element *maint_cplus_cmd_list;
 
 char *gdb_demangle (const char *name, int options);
 
+/* Like gdb_demangle, but suitable for use as la_demangle_for_symbol.  */
+
+char *gdb_demangle_for_symbol (const char *mangled, int *recognized);
+
 #endif /* CP_SUPPORT_H */
diff --git a/gdb/d-lang.c b/gdb/d-lang.c
index b25136d..21d379e 100644
--- a/gdb/d-lang.c
+++ b/gdb/d-lang.c
@@ -55,6 +55,14 @@  d_demangle (const char *symbol, int options)
   return gdb_demangle (symbol, options | DMGL_DLANG);
 }
 
+/* la_demangle_for_symbol implementation for D.  */
+
+static char *
+d_demangle_for_symbol (const char *mangled, int *recognized)
+{
+  return d_demangle (mangled, 0);
+}
+
 /* Table mapping opcodes into strings for printing operators
    and precedences of the operators.  */
 static const struct op_print d_op_print_tab[] =
@@ -223,6 +231,7 @@  static const struct language_defn d_language_defn =
   d_lookup_symbol_nonlocal,
   basic_lookup_transparent_type,
   d_demangle,			/* Language specific symbol demangler.  */
+  d_demangle_for_symbol,
   NULL,				/* Language specific
 				   class_name_from_physname.  */
   d_op_print_tab,		/* Expression operators for printing.  */
diff --git a/gdb/defs.h b/gdb/defs.h
index ed51396..15d3805 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -194,26 +194,29 @@  extern void quit_serial_event_clear (void);
 /* * Languages represented in the symbol table and elsewhere.
    This should probably be in language.h, but since enum's can't
    be forward declared to satisfy opaque references before their
-   actual definition, needs to be here.  */
+   actual definition, needs to be here.
+
+   The constants here are in priority order.  In particular,
+   demangling is attempted according to this order.  */
 
 enum language
   {
     language_unknown,		/* Language not known */
     language_auto,		/* Placeholder for automatic setting */
     language_c,			/* C */
+    language_objc,		/* Objective-C */
     language_cplus,		/* C++ */
+    language_java,		/* Java */
     language_d,			/* D */
     language_go,		/* Go */
-    language_objc,		/* Objective-C */
-    language_java,		/* Java */
     language_fortran,		/* Fortran */
     language_m2,		/* Modula-2 */
     language_asm,		/* Assembly language */
     language_pascal,		/* Pascal */
-    language_ada,		/* Ada */
     language_opencl,		/* OpenCL */
     language_rust,		/* Rust */
     language_minimal,		/* All other languages, minimal support only */
+    language_ada,		/* Ada */
     nr_languages
   };
 
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 719083b..58f58dd 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -268,7 +268,14 @@  const struct language_defn f_language_defn =
   NULL,                    	/* name_of_this */
   cp_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
+
+  /* We could support demangling here to provide module namespaces
+     also for inferiors with only minimal symbol table (ELF symbols).
+     Just the mangling standard is not standardized across compilers
+     and there is no DW_AT_producer available for inferiors with only
+     the ELF symbols to check the mangling kind.  */
   NULL,				/* Language specific symbol demangler */
+  NULL,
   NULL,				/* Language specific
 				   class_name_from_physname */
   f_op_print_tab,		/* expression operators for printing */
diff --git a/gdb/go-lang.c b/gdb/go-lang.c
index 15ca78b..152cf87 100644
--- a/gdb/go-lang.c
+++ b/gdb/go-lang.c
@@ -385,6 +385,14 @@  go_demangle (const char *mangled_name, int options)
   return result;
 }
 
+/* la_demangle_for_symbol for Go.  */
+
+static char *
+go_demangle_for_symbol (const char *mangled, int *recognized)
+{
+  return go_demangle (mangled, 0);
+}
+
 /* Given a Go symbol, return its package or NULL if unknown.
    Space for the result is malloc'd, caller must free.  */
 
@@ -584,6 +592,7 @@  static const struct language_defn go_language_defn =
   basic_lookup_symbol_nonlocal, 
   basic_lookup_transparent_type,
   go_demangle,			/* Language specific symbol demangler.  */
+  go_demangle_for_symbol,
   NULL,				/* Language specific
 				   class_name_from_physname.  */
   go_op_print_tab,		/* Expression operators for printing.  */
diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c
index 797a7f0..b3f998d 100644
--- a/gdb/jv-lang.c
+++ b/gdb/jv-lang.c
@@ -1018,6 +1018,14 @@  static char *java_demangle (const char *mangled, int options)
   return gdb_demangle (mangled, options | DMGL_JAVA);
 }
 
+/* la_demangle_for_symbol for Java.  */
+
+static char *
+java_demangle_for_symbol (const char *mangled, int *recognized)
+{
+  return java_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
+}
+
 /* Find the member function name of the demangled name NAME.  NAME
    must be a method name including arguments, in order to correctly
    locate the last component.
@@ -1194,6 +1202,7 @@  const struct language_defn java_language_defn =
   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   java_demangle,		/* Language specific symbol demangler */
+  java_demangle_for_symbol,
   java_class_name_from_physname,/* Language specific class name */
   java_op_print_tab,		/* expression operators for printing */
   0,				/* not c-style arrays */
diff --git a/gdb/language.c b/gdb/language.c
index 02e21ca..48faca7 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -663,6 +663,21 @@  language_demangle (const struct language_defn *current_language,
   return NULL;
 }
 
+/* See langauge.h.  */
+
+char *
+language_demangle_for_symbol (const struct language_defn *lang,
+			      const char *mangled, int *recognized)
+{
+  gdb_assert (lang != NULL);
+
+  *recognized = 0;
+  if (lang->la_demangle_for_symbol == NULL)
+    return NULL;
+
+  return lang->la_demangle_for_symbol (mangled, recognized);
+}
+
 /* Return class name from physname or NULL.  */
 char *
 language_class_name_from_physname (const struct language_defn *lang,
@@ -843,6 +858,7 @@  const struct language_defn unknown_language_defn =
   basic_lookup_symbol_nonlocal, /* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   unk_lang_demangle,		/* Language specific symbol demangler */
+  NULL,
   unk_lang_class_name,		/* Language specific
 				   class_name_from_physname */
   unk_op_print_tab,		/* expression operators for printing */
@@ -891,6 +907,7 @@  const struct language_defn auto_language_defn =
   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   unk_lang_demangle,		/* Language specific symbol demangler */
+  NULL,
   unk_lang_class_name,		/* Language specific
 				   class_name_from_physname */
   unk_op_print_tab,		/* expression operators for printing */
@@ -937,6 +954,7 @@  const struct language_defn local_language_defn =
   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   unk_lang_demangle,		/* Language specific symbol demangler */
+  NULL,
   unk_lang_class_name,		/* Language specific
 				   class_name_from_physname */
   unk_op_print_tab,		/* expression operators for printing */
diff --git a/gdb/language.h b/gdb/language.h
index d57c60e..f6ffe88 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -292,6 +292,19 @@  struct language_defn
     /* Return demangled language symbol, or NULL.  */
     char *(*la_demangle) (const char *mangled, int options);
 
+    /* Demangle a symbol according to this language's rules.  Unlike
+       la_demangle, this does not take any options.  The return value
+       should either be NULL if the name cannot be demangled, or an
+       xmalloc'd string, to be owned by the caller.
+
+       If this function returns non-NULL, then it can be assumed that
+       MANGLED represents a mangled symbol for this language.  If this
+       function returns NULL, then normally the converse is true, but
+       RECOGNIZED can be set to 1 to override this.
+       
+       RECOGNIZED must be initialized to 0 by the caller.  */
+    char *(*la_demangle_for_symbol) (const char *mangled, int *recognized);
+
     /* Return class name of a mangled method name or NULL.  */
     char *(*la_class_name_from_physname) (const char *physname);
 
@@ -565,6 +578,13 @@  extern CORE_ADDR skip_language_trampoline (struct frame_info *, CORE_ADDR pc);
 extern char *language_demangle (const struct language_defn *current_language, 
 				const char *mangled, int options);
 
+/* A wrapper for la_demangle_for_symbol that initializes RECOGNIZED
+   first.  The arguments and result are as for the method.  */
+
+extern char *language_demangle_for_symbol (const struct language_defn *lang,
+					   const char *mangled,
+					   int *recognized);
+
 /* Return class name from physname, or NULL.  */
 extern char *language_class_name_from_physname (const struct language_defn *,
 					        const char *physname);
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index 4626bfc..67d0f6b 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -381,6 +381,7 @@  const struct language_defn m2_language_defn =
   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   NULL,				/* Language specific symbol demangler */
+  NULL,
   NULL,				/* Language specific
 				   class_name_from_physname */
   m2_op_print_tab,		/* expression operators for printing */
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index fe3e082..5abfc13 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -281,6 +281,14 @@  objc_demangle (const char *mangled, int options)
     return NULL;	/* Not an objc mangled name.  */
 }
 
+/* la_demangle_for_symbol for ObjC.  */
+
+static char *
+objc_demangle_for_symbol (const char *mangled, int *recognized)
+{
+  return objc_demangle (mangled, 0);
+}
+
 /* Determine if we are currently in the Objective-C dispatch function.
    If so, get the address of the method function that the dispatcher
    would call and use that as the function to step into instead.  Also
@@ -381,6 +389,7 @@  const struct language_defn objc_language_defn = {
   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   objc_demangle,		/* Language specific symbol demangler */
+  objc_demangle_for_symbol,
   NULL,				/* Language specific
 				   class_name_from_physname */
   objc_op_print_tab,		/* Expression operators for printing */
diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
index 74651bc..2a46d86 100644
--- a/gdb/opencl-lang.c
+++ b/gdb/opencl-lang.c
@@ -1070,6 +1070,7 @@  const struct language_defn opencl_language_defn =
   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   NULL,				/* Language specific symbol demangler */
+  NULL,
   NULL,				/* Language specific
 				   class_name_from_physname */
   c_op_print_tab,		/* expression operators for printing */
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index 0897be2..86e787b 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -444,6 +444,7 @@  const struct language_defn pascal_language_defn =
   basic_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   NULL,				/* Language specific symbol demangler */
+  NULL,
   NULL,				/* Language specific class_name_from_physname */
   pascal_op_print_tab,		/* expression operators for printing */
   1,				/* c-style arrays */
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 36dab67..b9215c8 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -25,6 +25,7 @@ 
 #include "c-lang.h"
 #include "charset.h"
 #include "cp-support.h"
+#include "demangle.h"
 #include "gdbarch.h"
 #include "infcall.h"
 #include "objfiles.h"
@@ -1988,6 +1989,16 @@  rust_lookup_symbol_nonlocal (const struct language_defn *langdef,
 
 
 
+/* la_demangle_for_symbol for Rust.  */
+
+static char *
+rust_demangle_for_symbol (const char *mangled, int *recognized)
+{
+  return gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
+}
+
+
+
 static const struct exp_descriptor exp_descriptor_rust = 
 {
   rust_print_subexp,
@@ -2030,6 +2041,7 @@  static const struct language_defn rust_language_defn =
   rust_lookup_symbol_nonlocal,	/* lookup_symbol_nonlocal */
   basic_lookup_transparent_type,/* lookup_transparent_type */
   gdb_demangle,			/* Language specific symbol demangler */
+  rust_demangle_for_symbol,
   NULL,				/* Language specific
 				   class_name_from_physname */
   c_op_print_tab,		/* expression operators for printing */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index f7a207a..1185723 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -747,111 +747,32 @@  symbol_find_demangled_name (struct general_symbol_info *gsymbol,
 			    const char *mangled)
 {
   char *demangled = NULL;
+  int i;
+  int recognized;
 
   if (gsymbol->language == language_unknown)
     gsymbol->language = language_auto;
 
-  if (gsymbol->language == language_objc
-      || gsymbol->language == language_auto)
-    {
-      demangled =
-	objc_demangle (mangled, 0);
-      if (demangled != NULL)
-	{
-	  gsymbol->language = language_objc;
-	  return demangled;
-	}
-    }
-  if (gsymbol->language == language_cplus
-      || gsymbol->language == language_rust
-      || gsymbol->language == language_auto)
-    {
-      demangled =
-        gdb_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
-      if (demangled != NULL)
-	{
-	  gsymbol->language = language_cplus;
-	  return demangled;
-	}
-    }
-  if (gsymbol->language == language_java)
+  if (gsymbol->language != language_auto)
     {
-      demangled =
-        gdb_demangle (mangled,
-		      DMGL_PARAMS | DMGL_ANSI | DMGL_JAVA);
-      if (demangled != NULL)
-	{
-	  gsymbol->language = language_java;
-	  return demangled;
-	}
-    }
-  if (gsymbol->language == language_d
-      || gsymbol->language == language_auto)
-    {
-      demangled = d_demangle(mangled, 0);
-      if (demangled != NULL)
-	{
-	  gsymbol->language = language_d;
-	  return demangled;
-	}
+      const struct language_defn *lang = language_def (gsymbol->language);
+
+      return language_demangle_for_symbol (lang, mangled, &recognized);
     }
-  /* FIXME(dje): Continually adding languages here is clumsy.
-     Better to just call la_demangle if !auto, and if auto then call
-     a utility routine that tries successive languages in turn and reports
-     which one it finds.  I realize the la_demangle options may be different
-     for different languages but there's already a FIXME for that.  */
-  if (gsymbol->language == language_go
-      || gsymbol->language == language_auto)
+
+  for (i = language_unknown; i < nr_languages; ++i)
     {
-      demangled = go_demangle (mangled, 0);
-      if (demangled != NULL)
+      enum language l = (enum language) i;
+      const struct language_defn *lang = language_def (l);
+
+      demangled = language_demangle_for_symbol (lang, mangled, &recognized);
+      if (demangled != NULL || recognized)
 	{
-	  gsymbol->language = language_go;
+	  gsymbol->language = l;
 	  return demangled;
 	}
     }
 
-  /* We could support `gsymbol->language == language_fortran' here to provide
-     module namespaces also for inferiors with only minimal symbol table (ELF
-     symbols).  Just the mangling standard is not standardized across compilers
-     and there is no DW_AT_producer available for inferiors with only the ELF
-     symbols to check the mangling kind.  */
-
-  /* Check for Ada symbols last.  See comment below explaining why.  */
-
-  if (gsymbol->language == language_auto)
-   {
-     const char *demangled = ada_decode (mangled);
-
-     if (demangled != mangled && demangled != NULL && demangled[0] != '<')
-       {
-	 /* Set the gsymbol language to Ada, but still return NULL.
-	    Two reasons for that:
-
-	      1. For Ada, we prefer computing the symbol's decoded name
-		 on the fly rather than pre-compute it, in order to save
-		 memory (Ada projects are typically very large).
-
-	      2. There are some areas in the definition of the GNAT
-		 encoding where, with a bit of bad luck, we might be able
-		 to decode a non-Ada symbol, generating an incorrect
-		 demangled name (Eg: names ending with "TB" for instance
-		 are identified as task bodies and so stripped from
-		 the decoded name returned).
-
-		 Returning NULL, here, helps us get a little bit of
-		 the best of both worlds.  Because we're last, we should
-		 not affect any of the other languages that were able to
-		 demangle the symbol before us; we get to correctly tag
-		 Ada symbols as such; and even if we incorrectly tagged
-		 a non-Ada symbol, which should be rare, any routing
-		 through the Ada language should be transparent (Ada
-		 tries to behave much like C/C++ with non-Ada symbols).  */
-	 gsymbol->language = language_ada;
-	 return NULL;
-       }
-   }
-
   return NULL;
 }