diff options
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/gdbtypes.c | 46 | ||||
-rw-r--r-- | gdb/gdbtypes.h | 6 | ||||
-rw-r--r-- | gdb/gnu-v2-abi.c | 31 | ||||
-rw-r--r-- | gdb/gnu-v3-abi.c | 19 | ||||
-rw-r--r-- | gdb/symfile.h | 2 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/gdb2384-base.cc | 12 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/gdb2384-base.h | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/gdb2384.cc | 22 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/gdb2384.exp | 100 |
11 files changed, 224 insertions, 38 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a05058c..59c4f26 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2008-02-03 Doug Evans <dje@google.com> + + PR 2384 + * gdbtypes.c (get_vptr_fieldno): Renamed from fill_in_vptr_fieldno. + Return basetype, fieldno if found. All callers updated. + Don't cache TYPE_VPTR_FIELDNO, TYPE_VPTR_BASETYPE if from different + objfile. + * gdbtypes.h (get_vptr_fieldno): Renamed from fill_in_vptr_fieldno. + * symfile.h (fill_in_vptr_fieldno): Delete. + 2008-02-02 Doug Evans <dje@google.com> * valarith.c (value_binop): Handle unsigned BINOP_REM division by zero. diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index a70b6e4..f444153 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -1288,15 +1288,19 @@ lookup_struct_elt_type (struct type *type, char *name, int noerr) return (struct type *) -1; /* For lint */ } -/* If possible, make the vptr_fieldno and vptr_basetype fields of TYPE - valid. Callers should be aware that in some cases (for example, +/* Lookup the vptr basetype/fieldno values for TYPE. + If found store vptr_basetype in *BASETYPEP if non-NULL, and return + vptr_fieldno. Also, if found and basetype is from the same objfile, + cache the results. + If not found, return -1 and ignore BASETYPEP. + Callers should be aware that in some cases (for example, the type or one of its baseclasses is a stub type and we are debugging a .o file), this function will not be able to find the virtual function table pointer, and vptr_fieldno will remain -1 and - vptr_basetype will remain NULL. */ + vptr_basetype will remain NULL or incomplete. */ -void -fill_in_vptr_fieldno (struct type *type) +int +get_vptr_fieldno (struct type *type, struct type **basetypep) { CHECK_TYPEDEF (type); @@ -1308,16 +1312,34 @@ fill_in_vptr_fieldno (struct type *type) is virtual (and hence we cannot share the table pointer). */ for (i = 0; i < TYPE_N_BASECLASSES (type); i++) { - struct type *baseclass = check_typedef (TYPE_BASECLASS (type, - i)); - fill_in_vptr_fieldno (baseclass); - if (TYPE_VPTR_FIELDNO (baseclass) >= 0) + struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i)); + int fieldno; + struct type *basetype; + + fieldno = get_vptr_fieldno (baseclass, &basetype); + if (fieldno >= 0) { - TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (baseclass); - TYPE_VPTR_BASETYPE (type) = TYPE_VPTR_BASETYPE (baseclass); - break; + /* If the type comes from a different objfile we can't cache + it, it may have a different lifetime. PR 2384 */ + if (TYPE_OBJFILE (type) == TYPE_OBJFILE (baseclass)) + { + TYPE_VPTR_FIELDNO (type) = fieldno; + TYPE_VPTR_BASETYPE (type) = basetype; + } + if (basetypep) + *basetypep = basetype; + return fieldno; } } + + /* Not found. */ + return -1; + } + else + { + if (basetypep) + *basetypep = TYPE_VPTR_BASETYPE (type); + return TYPE_VPTR_FIELDNO (type); } } diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index d224140..f829cc7 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -375,7 +375,9 @@ struct main_type /* Field number of the virtual function table pointer in VPTR_BASETYPE. If -1, we were unable to find the virtual function table pointer in initial symbol reading, and - fill_in_vptr_fieldno should be called to find it if possible. + get_vptr_fieldno should be called to find it if possible. + get_vptr_fieldno will update this field if possible. + Otherwise the value is left at -1. Unused if this type does not have virtual functions. */ @@ -1274,7 +1276,7 @@ extern struct type *lookup_typename (char *, struct block *, int); extern struct type *lookup_template_type (char *, struct type *, struct block *); -extern void fill_in_vptr_fieldno (struct type *); +extern int get_vptr_fieldno (struct type *, struct type **); extern int get_destructor_fn_field (struct type *, int *, int *); diff --git a/gdb/gnu-v2-abi.c b/gdb/gnu-v2-abi.c index 6623813..9cc34e6 100644 --- a/gdb/gnu-v2-abi.c +++ b/gdb/gnu-v2-abi.c @@ -89,8 +89,6 @@ gnuv2_virtual_fn_field (struct value **arg1p, struct fn_field * f, int j, { struct value *arg1 = *arg1p; struct type *type1 = check_typedef (value_type (arg1)); - - struct type *entry_type; /* First, get the virtual function table pointer. That comes with a strange type, so cast it to type `pointer to long' (which @@ -103,6 +101,9 @@ gnuv2_virtual_fn_field (struct value **arg1p, struct fn_field * f, int j, (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j)); struct type *fcontext = TYPE_FN_FIELD_FCONTEXT (f, j); struct type *context; + struct type *context_vptr_basetype; + int context_vptr_fieldno; + if (fcontext == NULL) /* We don't have an fcontext (e.g. the program was compiled with g++ version 1). Try to get the vtbl from the TYPE_VPTR_BASETYPE. @@ -124,13 +125,13 @@ gnuv2_virtual_fn_field (struct value **arg1p, struct fn_field * f, int j, /* This type may have been defined before its virtual function table was. If so, fill in the virtual function table entry for the type now. */ - if (TYPE_VPTR_FIELDNO (context) < 0) - fill_in_vptr_fieldno (context); + context_vptr_fieldno = get_vptr_fieldno (context, &context_vptr_basetype); + /* FIXME: What to do if vptr_fieldno is still -1? */ /* The virtual function table is now an array of structures which have the form { int16 offset, delta; void *pfn; }. */ - vtbl = value_primitive_field (arg1, 0, TYPE_VPTR_FIELDNO (context), - TYPE_VPTR_BASETYPE (context)); + vtbl = value_primitive_field (arg1, 0, context_vptr_fieldno, + context_vptr_basetype); /* With older versions of g++, the vtbl field pointed to an array of structures. Nowadays it points directly to the structure. */ @@ -195,6 +196,8 @@ gnuv2_value_rtti_type (struct value *v, int *full, int *top, int *using_enc) struct symbol *sym; char *demangled_name, *p; struct type *btype; + struct type *known_type_vptr_basetype; + int known_type_vptr_fieldno; if (full) *full = 0; @@ -215,18 +218,18 @@ gnuv2_value_rtti_type (struct value *v, int *full, int *top, int *using_enc) the type info functions, which are always right. Deal with it until then. */ - /* If the type has no vptr fieldno, try to get it filled in */ - if (TYPE_VPTR_FIELDNO(known_type) < 0) - fill_in_vptr_fieldno(known_type); + /* Try to get the vptr basetype, fieldno. */ + known_type_vptr_fieldno = get_vptr_fieldno (known_type, + &known_type_vptr_basetype); - /* If we still can't find one, give up */ - if (TYPE_VPTR_FIELDNO(known_type) < 0) + /* If we can't find it, give up. */ + if (known_type_vptr_fieldno < 0) return NULL; /* Make sure our basetype and known type match, otherwise, cast so we can get at the vtable properly. */ - btype = TYPE_VPTR_BASETYPE (known_type); + btype = known_type_vptr_basetype; CHECK_TYPEDEF (btype); if (btype != known_type ) { @@ -239,10 +242,10 @@ gnuv2_value_rtti_type (struct value *v, int *full, int *top, int *using_enc) we'd waste a bunch of time figuring out we already know the type. Besides, we don't care about the type, just the actual pointer */ - if (VALUE_ADDRESS (value_field (v, TYPE_VPTR_FIELDNO (known_type))) == 0) + if (VALUE_ADDRESS (value_field (v, known_type_vptr_fieldno)) == 0) return NULL; - vtbl=value_as_address(value_field(v,TYPE_VPTR_FIELDNO(known_type))); + vtbl = value_as_address (value_field (v, known_type_vptr_fieldno)); /* Try to find a symbol that is the vtable */ minsym=lookup_minimal_symbol_by_pc(vtbl); diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index fa25126..2059f30 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -201,6 +201,8 @@ gnuv3_rtti_type (struct value *value, struct type *run_time_type; struct type *base_type; LONGEST offset_to_top; + struct type *values_type_vptr_basetype; + int values_type_vptr_fieldno; /* We only have RTTI for class objects. */ if (TYPE_CODE (values_type) != TYPE_CODE_CLASS) @@ -208,8 +210,9 @@ gnuv3_rtti_type (struct value *value, /* If we can't find the virtual table pointer for values_type, we can't find the RTTI. */ - fill_in_vptr_fieldno (values_type); - if (TYPE_VPTR_FIELDNO (values_type) == -1) + values_type_vptr_fieldno = get_vptr_fieldno (values_type, + &values_type_vptr_basetype); + if (values_type_vptr_fieldno == -1) return NULL; if (using_enc_p) @@ -217,7 +220,7 @@ gnuv3_rtti_type (struct value *value, /* Fetch VALUE's virtual table pointer, and tweak it to point at an instance of our imaginary gdb_gnu_v3_abi_vtable structure. */ - base_type = check_typedef (TYPE_VPTR_BASETYPE (values_type)); + base_type = check_typedef (values_type_vptr_basetype); if (values_type != base_type) { value = value_cast (base_type, value); @@ -225,7 +228,7 @@ gnuv3_rtti_type (struct value *value, *using_enc_p = 1; } vtable_address - = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (values_type))); + = value_as_address (value_field (value, values_type_vptr_fieldno)); vtable = value_at_lazy (vtable_type, vtable_address - vtable_address_point_offset ()); @@ -381,6 +384,7 @@ gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr, struct value *offset_val, *vbase_array; CORE_ADDR vtable_address; long int cur_base_offset, base_offset; + int vbasetype_vptr_fieldno; /* If it isn't a virtual base, this is easy. The offset is in the type definition. */ @@ -414,11 +418,10 @@ gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr, we have debugging information for that baseclass. */ vbasetype = TYPE_VPTR_BASETYPE (type); - if (TYPE_VPTR_FIELDNO (vbasetype) < 0) - fill_in_vptr_fieldno (vbasetype); + vbasetype_vptr_fieldno = get_vptr_fieldno (vbasetype, NULL); - if (TYPE_VPTR_FIELDNO (vbasetype) >= 0 - && TYPE_FIELD_BITPOS (vbasetype, TYPE_VPTR_FIELDNO (vbasetype)) != 0) + if (vbasetype_vptr_fieldno >= 0 + && TYPE_FIELD_BITPOS (vbasetype, vbasetype_vptr_fieldno) != 0) error (_("Illegal vptr offset in class %s"), TYPE_NAME (vbasetype) ? TYPE_NAME (vbasetype) : "<unknown>"); diff --git a/gdb/symfile.h b/gdb/symfile.h index 5ff53f8..948cef7 100644 --- a/gdb/symfile.h +++ b/gdb/symfile.h @@ -207,8 +207,6 @@ extern struct symtab *allocate_symtab (char *, struct objfile *); extern int free_named_symtabs (char *); -extern void fill_in_vptr_fieldno (struct type *); - extern void add_symtab_fns (struct sym_fns *); extern void syms_from_objfile (struct objfile *, diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 10e4a03..22c7030 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2008-02-03 Doug Evans <dje@google.com> + + * gdb.cp/gdb2384.exp: New file. + * gdb.cp/gdb2384.cc: New file. + * gdb.cp/gdb2384-base.h: New file. + * gdb.cp/gdb2384-base.cc: New file. + 2008-02-02 Doug Evans <dje@google.com> * gdb.base/sigall.c (main): Ensure all signals aren't blocked. diff --git a/gdb/testsuite/gdb.cp/gdb2384-base.cc b/gdb/testsuite/gdb.cp/gdb2384-base.cc new file mode 100644 index 0000000..5dc4c65 --- /dev/null +++ b/gdb/testsuite/gdb.cp/gdb2384-base.cc @@ -0,0 +1,12 @@ +#include "gdb2384-base.h" + +base::base (int _x) + : x (_x) +{ +} + +int +base::meth () +{ + return x; +} diff --git a/gdb/testsuite/gdb.cp/gdb2384-base.h b/gdb/testsuite/gdb.cp/gdb2384-base.h new file mode 100644 index 0000000..3519816 --- /dev/null +++ b/gdb/testsuite/gdb.cp/gdb2384-base.h @@ -0,0 +1,7 @@ +class base +{ + public: + base (int _x); + int x; + virtual int meth (); +}; diff --git a/gdb/testsuite/gdb.cp/gdb2384.cc b/gdb/testsuite/gdb.cp/gdb2384.cc new file mode 100644 index 0000000..81cfcb5 --- /dev/null +++ b/gdb/testsuite/gdb.cp/gdb2384.cc @@ -0,0 +1,22 @@ +#include "gdb2384-base.h" + +class derived : public base +{ + public: + derived (int); +}; + +derived::derived (int _x) + : base (_x) +{ +} + +int g; + +int +main () +{ + derived d (42); + g = d.meth (); // set breakpoint here + return 0; +} diff --git a/gdb/testsuite/gdb.cp/gdb2384.exp b/gdb/testsuite/gdb.cp/gdb2384.exp new file mode 100644 index 0000000..370c65b --- /dev/null +++ b/gdb/testsuite/gdb.cp/gdb2384.exp @@ -0,0 +1,100 @@ +# Copyright 2007 Free Software Foundation, Inc. + +# 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 3 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, see <http://www.gnu.org/licenses/>. + +# When gdb resolves type information for class "derived" from objfile +# gdb2384, it use to fill in the TYPE_VPTR_BASETYPE field with class "base" +# from objfile gdb2384-base.so. When the program is rerun the type +# information for base-in-so-base.so is discarded leaving +# TYPE_VPTR_BASETYPE dangling. + +if $tracelevel then { + strace $tracelevel +} + +if { [skip_cplus_tests] } { continue } +if { [skip_shlib_tests] } { continue } + +set prms_id 2384 +set bug_id 0 + +set testfile "gdb2384" +set srcfile ${testfile}.cc +set binfile $objdir/$subdir/$testfile + +set libfile "gdb2384-base" +set libsrcfile ${libfile}.cc +set sofile $objdir/$subdir/${libfile}.so + +# Create and source the file that provides information about the compiler +# used to compile the test case. +if [get_compiler_info ${binfile} "c++"] { + return -1 +} + +if { [gdb_compile_shlib $srcdir/$subdir/$libsrcfile $sofile {debug c++}] != "" + || [gdb_compile $srcdir/$subdir/$srcfile $binfile executable [list debug "c++" shlib=${sofile}]] != ""} { + untested gdb2384.exp + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} +gdb_load_shlibs ${sofile} + +set bp_location [gdb_get_line_number "set breakpoint here"] + +# Set a breakpoint with multiple locations. + +gdb_test "break $srcfile:$bp_location" \ + "Breakpoint.*at.* file .*$srcfile, line.*" \ + "set breakpoint" + +gdb_run_cmd +gdb_expect { + -re "Breakpoint \[0-9\]+,.*main \\(.*\\).*$gdb_prompt $" { + pass "run to breakpoint" + } + -re "$gdb_prompt $" { + fail "run to breakpoint" + } + timeout { + fail "run to breakpoint (timeout)" + } +} + +gdb_test "print d.meth ()" \ + ".*42.*" \ + "print d.meth ()" + +# Now try again. gdb's without the fix will hopefully segv here + +gdb_run_cmd +gdb_expect { + -re "Breakpoint \[0-9\]+,.*main \\(.*\\).*$gdb_prompt $" { + pass "run to breakpoint #2" + } + -re "$gdb_prompt $" { + fail "run to breakpoint #2" + } + timeout { + fail "run to breakpoint #2 (timeout)" + } +} + +gdb_test "print d.meth ()" \ + ".*42.*" \ + "gdb2384" |