aboutsummaryrefslogtreecommitdiff
path: root/gdb/stabsread.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/stabsread.c')
-rw-r--r--gdb/stabsread.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/gdb/stabsread.c b/gdb/stabsread.c
index 6011769..4697b40 100644
--- a/gdb/stabsread.c
+++ b/gdb/stabsread.c
@@ -44,6 +44,8 @@
#include "demangle.h"
#include "language.h"
#include "doublest.h"
+#include "cp-abi.h"
+#include "cp-support.h"
#include <ctype.h>
@@ -3080,6 +3082,27 @@ rs6000_builtin_type (int typenum)
/* This page contains subroutines of read_type. */
+/* Replace *OLD_NAME with the method name portion of PHYSNAME. */
+
+static void
+update_method_name_from_physname (char **old_name, char *physname)
+{
+ char *method_name;
+
+ method_name = method_name_from_physname (physname);
+
+ if (method_name == NULL)
+ error ("bad physname %s\n", physname);
+
+ if (strcmp (*old_name, method_name) != 0)
+ {
+ xfree (*old_name);
+ *old_name = method_name;
+ }
+ else
+ xfree (method_name);
+}
+
/* Read member function stabs info for C++ classes. The form of each member
function data is:
@@ -3377,6 +3400,164 @@ read_member_functions (struct field_info *fip, char **pp, struct type *type,
}
else
{
+ int has_stub = 0;
+ int has_destructor = 0, has_other = 0;
+ int is_v3 = 0;
+ struct next_fnfield *tmp_sublist;
+
+ /* Various versions of GCC emit various mostly-useless
+ strings in the name field for special member functions.
+
+ For stub methods, we need to defer correcting the name
+ until we are ready to unstub the method, because the current
+ name string is used by gdb_mangle_name. The only stub methods
+ of concern here are GNU v2 operators; other methods have their
+ names correct (see caveat below).
+
+ For non-stub methods, in GNU v3, we have a complete physname.
+ Therefore we can safely correct the name now. This primarily
+ affects constructors and destructors, whose name will be
+ __comp_ctor or __comp_dtor instead of Foo or ~Foo. Cast
+ operators will also have incorrect names; for instance,
+ "operator int" will be named "operator i" (i.e. the type is
+ mangled).
+
+ For non-stub methods in GNU v2, we have no easy way to
+ know if we have a complete physname or not. For most
+ methods the result depends on the platform (if CPLUS_MARKER
+ can be `$' or `.', it will use minimal debug information, or
+ otherwise the full physname will be included).
+
+ Rather than dealing with this, we take a different approach.
+ For v3 mangled names, we can use the full physname; for v2,
+ we use cplus_demangle_opname (which is actually v2 specific),
+ because the only interesting names are all operators - once again
+ barring the caveat below. Skip this process if any method in the
+ group is a stub, to prevent our fouling up the workings of
+ gdb_mangle_name.
+
+ The caveat: GCC 2.95.x (and earlier?) put constructors and
+ destructors in the same method group. We need to split this
+ into two groups, because they should have different names.
+ So for each method group we check whether it contains both
+ routines whose physname appears to be a destructor (the physnames
+ for and destructors are always provided, due to quirks in v2
+ mangling) and routines whose physname does not appear to be a
+ destructor. If so then we break up the list into two halves.
+ Even if the constructors and destructors aren't in the same group
+ the destructor will still lack the leading tilde, so that also
+ needs to be fixed.
+
+ So, to summarize what we expect and handle here:
+
+ Given Given Real Real Action
+ method name physname physname method name
+
+ __opi [none] __opi__3Foo operator int opname
+ [now or later]
+ Foo _._3Foo _._3Foo ~Foo separate and
+ rename
+ operator i _ZN3FoocviEv _ZN3FoocviEv operator int demangle
+ __comp_ctor _ZN3FooC1ERKS_ _ZN3FooC1ERKS_ Foo demangle
+ */
+
+ tmp_sublist = sublist;
+ while (tmp_sublist != NULL)
+ {
+ if (tmp_sublist->fn_field.is_stub)
+ has_stub = 1;
+ if (tmp_sublist->fn_field.physname[0] == '_'
+ && tmp_sublist->fn_field.physname[1] == 'Z')
+ is_v3 = 1;
+
+ if (is_destructor_name (tmp_sublist->fn_field.physname))
+ has_destructor++;
+ else
+ has_other++;
+
+ tmp_sublist = tmp_sublist->next;
+ }
+
+ if (has_destructor && has_other)
+ {
+ struct next_fnfieldlist *destr_fnlist;
+ struct next_fnfield *last_sublist;
+
+ /* Create a new fn_fieldlist for the destructors. */
+
+ destr_fnlist = (struct next_fnfieldlist *)
+ xmalloc (sizeof (struct next_fnfieldlist));
+ make_cleanup (xfree, destr_fnlist);
+ memset (destr_fnlist, 0, sizeof (struct next_fnfieldlist));
+ destr_fnlist->fn_fieldlist.name
+ = obconcat (&objfile->type_obstack, "", "~",
+ new_fnlist->fn_fieldlist.name);
+
+ destr_fnlist->fn_fieldlist.fn_fields = (struct fn_field *)
+ obstack_alloc (&objfile->type_obstack,
+ sizeof (struct fn_field) * has_destructor);
+ memset (destr_fnlist->fn_fieldlist.fn_fields, 0,
+ sizeof (struct fn_field) * has_destructor);
+ tmp_sublist = sublist;
+ last_sublist = NULL;
+ i = 0;
+ while (tmp_sublist != NULL)
+ {
+ if (!is_destructor_name (tmp_sublist->fn_field.physname))
+ {
+ tmp_sublist = tmp_sublist->next;
+ continue;
+ }
+
+ destr_fnlist->fn_fieldlist.fn_fields[i++]
+ = tmp_sublist->fn_field;
+ if (last_sublist)
+ last_sublist->next = tmp_sublist->next;
+ else
+ sublist = tmp_sublist->next;
+ last_sublist = tmp_sublist;
+ tmp_sublist = tmp_sublist->next;
+ }
+
+ destr_fnlist->fn_fieldlist.length = has_destructor;
+ destr_fnlist->next = fip->fnlist;
+ fip->fnlist = destr_fnlist;
+ nfn_fields++;
+ total_length += has_destructor;
+ length -= has_destructor;
+ }
+ else if (is_v3)
+ {
+ /* v3 mangling prevents the use of abbreviated physnames,
+ so we can do this here. There are stubbed methods in v3
+ only:
+ - in -gstabs instead of -gstabs+
+ - or for static methods, which are output as a function type
+ instead of a method type. */
+
+ update_method_name_from_physname (&new_fnlist->fn_fieldlist.name,
+ sublist->fn_field.physname);
+ }
+ else if (has_destructor && new_fnlist->fn_fieldlist.name[0] != '~')
+ {
+ new_fnlist->fn_fieldlist.name = concat ("~", main_fn_name, NULL);
+ xfree (main_fn_name);
+ }
+ else if (!has_stub)
+ {
+ char dem_opname[256];
+ int ret;
+ ret = cplus_demangle_opname (new_fnlist->fn_fieldlist.name,
+ dem_opname, DMGL_ANSI);
+ if (!ret)
+ ret = cplus_demangle_opname (new_fnlist->fn_fieldlist.name,
+ dem_opname, 0);
+ if (ret)
+ new_fnlist->fn_fieldlist.name
+ = obsavestring (dem_opname, strlen (dem_opname),
+ &objfile->type_obstack);
+ }
+
new_fnlist->fn_fieldlist.fn_fields = (struct fn_field *)
obstack_alloc (&objfile->type_obstack,
sizeof (struct fn_field) * length);