* gdbtypes.c (check_stub_method): Make static.

(check_stub_method_group): New function.
        * gdbtypes.h: Update prototypes.
        * cp-support.c: New file.
        * cp-support.h: New file.

        * stabsread.c: Include "cp-abi.h" and "cp-support.h".
        (update_method_name_from_physname): New function.
        (read_member_functions): Correct method names for operators
        and v3 constructors/destructors.  Separate v2 constructors and
        destructors.
        * Makefile.in (stabsread.o): Update dependencies.
        (SFILES): Add cp-support.c.
        (COMMON_OBS): Add cp-support.o.
        (cp_support_h, cp-support.o): Add.

        * cp-valprint.c (cp_print_class_method): Call
        check_stub_method_group instead of check_stub_method.  Remove
        extraneous QUITs.
        * p-valprint.c (pascal_object_print_class_method): Likewise.
        * valops.c (search_struct_method): Likewise.
        (find_method_list, value_struct_elt_for_reference): Likewise.
This commit is contained in:
Daniel Jacobowitz 2002-09-14 02:09:39 +00:00
parent 94202ba54e
commit de17c821b3
10 changed files with 433 additions and 37 deletions

View File

@ -1,3 +1,28 @@
2002-09-13 Daniel Jacobowitz <drow@mvista.com>
* gdbtypes.c (check_stub_method): Make static.
(check_stub_method_group): New function.
* gdbtypes.h: Update prototypes.
* cp-support.c: New file.
* cp-support.h: New file.
* stabsread.c: Include "cp-abi.h" and "cp-support.h".
(update_method_name_from_physname): New function.
(read_member_functions): Correct method names for operators
and v3 constructors/destructors. Separate v2 constructors and
destructors.
* Makefile.in (stabsread.o): Update dependencies.
(SFILES): Add cp-support.c.
(COMMON_OBS): Add cp-support.o.
(cp_support_h, cp-support.o): Add.
* cp-valprint.c (cp_print_class_method): Call
check_stub_method_group instead of check_stub_method. Remove
extraneous QUITs.
* p-valprint.c (pascal_object_print_class_method): Likewise.
* valops.c (search_struct_method): Likewise.
(find_method_list, value_struct_elt_for_reference): Likewise.
2002-09-13 Andrew Cagney <cagney@redhat.com>
* gdbarch.sh (SIGTRAMP_END): Change to a predicate function.

View File

@ -558,7 +558,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
ui-file.h ui-file.c \
frame.c doublest.c \
builtin-regs.c std-regs.c \
gnu-v2-abi.c gnu-v3-abi.c hpacc-abi.c cp-abi.c
gnu-v2-abi.c gnu-v3-abi.c hpacc-abi.c cp-abi.c cp-support.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@ -626,6 +626,7 @@ command_h = command.h
complaints_h = complaints.h
completer_h = completer.h
cp_abi_h = cp-abi.h
cp_support_h = cp-support.h
dcache_h = dcache.h
defs_h = defs.h $(config_h) $(gdb_locale_h) $(gdb_signals_h) $(ansidecl_h) \
$(libiberty_h) $(progress_h) $(bfd_h) $(tui_h) $(ui_file_h) $(xm_h) \
@ -842,7 +843,7 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \
nlmread.o serial.o mdebugread.o top.o utils.o \
ui-file.o \
frame.o doublest.o \
gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o
gnu-v2-abi.o gnu-v3-abi.o hpacc-abi.o cp-abi.o cp-support.o
OBS = $(COMMON_OBS) $(ANNOTATE_OBS)
@ -1588,6 +1589,7 @@ corelow.o: corelow.c $(defs_h) $(gdb_string_h) $(frame_h) $(inferior_h) \
$(symtab_h) $(command_h) $(bfd_h) $(target_h) $(gdbcore_h) \
$(gdbthread_h) $(regcache_h) $(symfile_h)
cp-abi.o: cp-abi.c $(defs_h) $(value_h) $(cp_abi_h) $(gdb_string_h)
cp-support.o: cp-support.c $(defs_h) $(cp_support_h)
cp-valprint.o: cp-valprint.c $(defs_h) $(gdb_obstack_h) $(symtab_h) \
$(gdbtypes_h) $(expression_h) $(value_h) $(command_h) $(gdbcmd_h) \
$(demangle_h) $(annotate_h) $(gdb_string_h) $(c_lang_h) $(target_h) \
@ -2174,7 +2176,7 @@ stabsread.o: stabsread.c $(defs_h) $(gdb_string_h) $(bfd_h) $(gdb_obstack_h) \
$(symtab_h) $(gdbtypes_h) $(expression_h) $(symfile_h) $(objfiles_h) \
$(aout_stab_gnu_h) $(libaout_h) $(aout_aout64_h) $(gdb_stabs_h) \
$(buildsym_h) $(complaints_h) $(demangle_h) $(language_h) \
$(doublest_h) $(stabsread_h)
$(doublest_h) $(stabsread_h) $(cp_abi_h) $(cp_support_h)
stack.o: stack.c $(defs_h) $(gdb_string_h) $(value_h) $(symtab_h) \
$(gdbtypes_h) $(expression_h) $(language_h) $(frame_h) $(gdbcmd_h) \
$(gdbcore_h) $(target_h) $(breakpoint_h) $(demangle_h) $(inferior_h) \

141
gdb/cp-support.c Normal file
View File

@ -0,0 +1,141 @@
/* Helper routines for C++ support in GDB.
Copyright 2002 Free Software Foundation, Inc.
Contributed by MontaVista Software.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "cp-support.h"
#include "gdb_string.h"
#include "demangle.h"
/* Find the last component of the demangled C++ name NAME. NAME
must be a method name including arguments, in order to correctly
locate the last component.
This function return a pointer to the first colon before the
last component, or NULL if the name had only one component. */
static const char *
find_last_component (const char *name)
{
const char *p;
int depth;
/* Functions can have local classes, so we need to find the
beginning of the last argument list, not the end of the first
one. */
p = name + strlen (name) - 1;
while (p > name && *p != ')')
p--;
if (p == name)
return NULL;
/* P now points at the `)' at the end of the argument list. Walk
back to the beginning. */
p--;
depth = 1;
while (p > name && depth > 0)
{
if (*p == '<' || *p == '(')
depth--;
else if (*p == '>' || *p == ')')
depth++;
p--;
}
if (p == name)
return NULL;
while (p > name && *p != ':')
p--;
if (p == name || p == name + 1 || p[-1] != ':')
return NULL;
return p - 1;
}
/* Return the name of the class containing method PHYSNAME. */
char *
class_name_from_physname (const char *physname)
{
char *ret = NULL;
const char *end;
int depth = 0;
char *demangled_name = cplus_demangle (physname, DMGL_ANSI);
if (demangled_name == NULL)
return NULL;
end = find_last_component (demangled_name);
if (end != NULL)
{
ret = xmalloc (end - demangled_name + 1);
memcpy (ret, demangled_name, end - demangled_name);
ret[end - demangled_name] = '\0';
}
xfree (demangled_name);
return ret;
}
/* Return the name of the method whose linkage name is PHYSNAME. */
char *
method_name_from_physname (const char *physname)
{
char *ret = NULL;
const char *end;
int depth = 0;
char *demangled_name = cplus_demangle (physname, DMGL_ANSI);
if (demangled_name == NULL)
return NULL;
end = find_last_component (demangled_name);
if (end != NULL)
{
char *args;
int len;
/* Skip "::". */
end = end + 2;
/* Find the argument list, if any. */
args = strchr (end, '(');
if (args == NULL)
len = strlen (end + 2);
else
{
args --;
while (*args == ' ')
args --;
len = args - end + 1;
}
ret = xmalloc (len + 1);
memcpy (ret, end, len);
ret[len] = 0;
}
xfree (demangled_name);
return ret;
}

25
gdb/cp-support.h Normal file
View File

@ -0,0 +1,25 @@
/* Helper routines for C++ support in GDB.
Copyright 2002 Free Software Foundation, Inc.
Contributed by MontaVista Software.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
extern char *class_name_from_physname (const char *physname);
extern char *method_name_from_physname (const char *physname);

View File

@ -97,13 +97,11 @@ cp_print_class_method (char *valaddr,
f = TYPE_FN_FIELDLIST1 (domain, i);
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
check_stub_method_group (domain, i);
for (j = 0; j < len2; j++)
{
QUIT;
if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
{
if (TYPE_FN_FIELD_STUB (f, j))
check_stub_method (domain, i, j);
kind = "virtual ";
goto common;
}
@ -129,15 +127,11 @@ cp_print_class_method (char *valaddr,
f = TYPE_FN_FIELDLIST1 (domain, i);
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
check_stub_method_group (f, j);
for (j = 0; j < len2; j++)
{
QUIT;
if (TYPE_FN_FIELD_STUB (f, j))
check_stub_method (domain, i, j);
if (STREQ (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
{
goto common;
}
goto common;
}
}
}

View File

@ -1672,7 +1672,7 @@ safe_parse_type (char *p, int length)
which info used to be in the stab's but was removed to hack back
the space required for them. */
void
static void
check_stub_method (struct type *type, int method_id, int signature_id)
{
struct fn_field *f;
@ -1781,6 +1781,49 @@ check_stub_method (struct type *type, int method_id, int signature_id)
xfree (demangled_name);
}
/* This is the external interface to check_stub_method, above. This function
unstubs all of the signatures for TYPE's METHOD_ID method name. After
calling this function TYPE_FN_FIELD_STUB will be cleared for each signature
and TYPE_FN_FIELDLIST_NAME will be correct.
This function unfortunately can not die until stabs do. */
void
check_stub_method_group (struct type *type, int method_id)
{
int len = TYPE_FN_FIELDLIST_LENGTH (type, method_id);
struct fn_field *f = TYPE_FN_FIELDLIST1 (type, method_id);
int j, found_stub;
for (j = 0; j < len; j++)
if (TYPE_FN_FIELD_STUB (f, j))
{
found_stub = 1;
check_stub_method (type, method_id, j);
}
/* GNU v3 methods with incorrect names were corrected when we read in
type information, because it was cheaper to do it then. The only GNU v2
methods with incorrect method names are operators and destructors;
destructors were also corrected when we read in type information.
Therefore the only thing we need to handle here are v2 operator
names. */
if (found_stub && strncmp (TYPE_FN_FIELD_PHYSNAME (f, 0), "_Z", 2) != 0)
{
int ret;
char dem_opname[256];
ret = cplus_demangle_opname (TYPE_FN_FIELDLIST_NAME (type, method_id),
dem_opname, DMGL_ANSI);
if (!ret)
ret = cplus_demangle_opname (TYPE_FN_FIELDLIST_NAME (type, method_id),
dem_opname, 0);
if (ret)
TYPE_FN_FIELDLIST_NAME (type, method_id) = xstrdup (dem_opname);
}
}
const struct cplus_struct_type cplus_struct_default;
void
@ -3435,7 +3478,6 @@ build_gdbtypes (void)
"__bfd_vma", (struct objfile *) NULL);
}
extern void _initialize_gdbtypes (void);
void
_initialize_gdbtypes (void)

View File

@ -1124,7 +1124,7 @@ extern struct type *check_typedef (struct type *);
#define CHECK_TYPEDEF(TYPE) (TYPE) = check_typedef (TYPE)
extern void check_stub_method (struct type *, int, int);
extern void check_stub_method_group (struct type *, int);
extern struct type *lookup_primitive_typename (char *);

View File

@ -620,13 +620,11 @@ pascal_object_print_class_method (char *valaddr, struct type *type,
f = TYPE_FN_FIELDLIST1 (domain, i);
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
check_stub_method_group (domain, i);
for (j = 0; j < len2; j++)
{
QUIT;
if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
{
if (TYPE_FN_FIELD_STUB (f, j))
check_stub_method (domain, i, j);
kind = "virtual ";
goto common;
}
@ -646,15 +644,11 @@ pascal_object_print_class_method (char *valaddr, struct type *type,
f = TYPE_FN_FIELDLIST1 (domain, i);
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
check_stub_method_group (domain, i);
for (j = 0; j < len2; j++)
{
QUIT;
if (TYPE_FN_FIELD_STUB (f, j))
check_stub_method (domain, i, j);
if (STREQ (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
{
goto common;
}
goto common;
}
}
}

View File

@ -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);

View File

@ -2302,12 +2302,11 @@ search_struct_method (char *name, struct value **arg1p,
struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
name_matched = 1;
check_stub_method_group (type, i);
if (j > 0 && args == 0)
error ("cannot resolve overloaded method `%s': no arguments supplied", name);
else if (j == 0 && args == 0)
{
if (TYPE_FN_FIELD_STUB (f, j))
check_stub_method (type, i, j);
v = value_fn_field (arg1p, f, j, type, offset);
if (v != NULL)
return v;
@ -2315,8 +2314,6 @@ search_struct_method (char *name, struct value **arg1p,
else
while (j >= 0)
{
if (TYPE_FN_FIELD_STUB (f, j))
check_stub_method (type, i, j);
if (!typecmp (TYPE_FN_FIELD_STATIC_P (f, j),
TYPE_VARARGS (TYPE_FN_FIELD_TYPE (f, j)),
TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (f, j)),
@ -2555,20 +2552,15 @@ find_method_list (struct value **argp, char *method, int offset,
char *fn_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
if (fn_field_name && (strcmp_iw (fn_field_name, method) == 0))
{
/* Resolve any stub methods. */
int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
int j;
*num_fns = len;
*basetype = type;
*boffset = offset;
for (j = 0; j < len; j++)
{
if (TYPE_FN_FIELD_STUB (f, j))
check_stub_method (type, i, j);
}
/* Resolve any stub methods. */
check_stub_method_group (type, i);
return f;
}
@ -3094,6 +3086,8 @@ value_struct_elt_for_reference (struct type *domain, int offset,
int j = TYPE_FN_FIELDLIST_LENGTH (t, i);
struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
check_stub_method_group (t, i);
if (intype == 0 && j > 1)
error ("non-unique member `%s' requires type instantiation", name);
if (intype)
@ -3107,8 +3101,6 @@ value_struct_elt_for_reference (struct type *domain, int offset,
else
j = 0;
if (TYPE_FN_FIELD_STUB (f, j))
check_stub_method (t, i, j);
if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
{
return value_from_longest