From 94603999f966820f5264e98e530cb59c38597963 Mon Sep 17 00:00:00 2001 From: John Gilmore Date: Tue, 6 Oct 1992 09:22:43 +0000 Subject: [PATCH] A bunch of changes mostly to improve debugging of C++ programs. Specifically, the calling of inferiors methods is improved. * value.h: New macros METHOD_PTR_IS_VIRTUAL, METHOD_PTR_FROM_VOFFSET, METHOD_PTR_TO_VOFFSET to partially hide the implementation details of pointer-to-method objects. How to tell if the pointer points to a virtual method is still very dependent on the particular compiler, but this should make it easier to find the places to change. * eval.c (evaluate_subexp [case OP_FUNCALL]), valprint.c (val_print [case TYPE_CODE_PTR]): Use the new METHOD_PTR_* macros, instead of a hard-wired-in code that incorrectly assumed a no-longerused representation of pointer-to-method values. And otherwise fix the relevant bit-rotted code. * valprint.c (type_print_base [case TYPE_CODE_STRUCT]): If there are both fields and methods, put a space between. * stabsread.c (read_struct_type): Fix bug in handling of GNU C++ anonymous type (indicated by CPLUS_MARKER followed by '_'). (It used to prematurely exit the loop reading in the fields, so it would think it should start reading methods while still in the fields. This could crash gdb given a gcc that can emit nested type information.) * valops.c (search_struct_method): Pass 'this' value by reference instead of by value. This provides a more consistent interface through a recursive search where the "bottom" functions may need to adjust offsets (due to multiple inheritance). * valops.c, value.h, values.c: Pass extra parameters to value_fn_field and value_virtual_fn_field so we can correctly adjust offset for multiple inheritance. * eval.c (evaluate_subexp [case OP_FUNCALL]): Simplify virtual function calls by using value_virtual_fn_field(). * values.c: New function baseclass_offset, derived from baseclass_addr (which perhaps can be made obsolete?). It returns an offset rather than an address. This is a cleaner interface since it doesn't mess around allocating new values. * valops.c (search_struct_method): Use baseclass_offset rather than baseclass_addr. --- gdb/ChangeLog | 45 ++++++++++++++++++++++ gdb/stabsread.c | 13 +++---- gdb/values.c | 100 +++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 142 insertions(+), 16 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c22a4aa9e13..4a08c2d31ca 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,48 @@ +Fri Sep 4 00:34:30 1992 Per Bothner (bothner@rtl.cygnus.com) + + A bunch of changes mostly to improve debugging of C++ programs. + Specifically, the calling of inferiors methods is improved. + + * value.h: New macros METHOD_PTR_IS_VIRTUAL, + METHOD_PTR_FROM_VOFFSET, METHOD_PTR_TO_VOFFSET to partially + hide the implementation details of pointer-to-method objects. + How to tell if the pointer points to a virtual method is + still very dependent on the particular compiler, but this + should make it easier to find the places to change. + * eval.c (evaluate_subexp [case OP_FUNCALL]), valprint.c + (val_print [case TYPE_CODE_PTR]): Use the new METHOD_PTR_* + macros, instead of a hard-wired-in code that incorrectly + assumed a no-longerused representation of pointer-to-method + values. And otherwise fix the relevant bit-rotted code. + + * valprint.c (type_print_base [case TYPE_CODE_STRUCT]): + If there are both fields and methods, put a space between. + + * stabsread.c (read_struct_type): Fix bug in handling of + GNU C++ anonymous type (indicated by CPLUS_MARKER followed + by '_'). (It used to prematurely exit the loop reading in + the fields, so it would think it should start reading + methods while still in the fields. This could crash gdb + given a gcc that can emit nested type information.) + + * valops.c (search_struct_method): Pass 'this' value by + reference instead of by value. This provides a more + consistent interface through a recursive search where the + "bottom" functions may need to adjust offsets (due to multiple + inheritance). + * valops.c, value.h, values.c: Pass extra parameters to + value_fn_field and value_virtual_fn_field so we can + correctly adjust offset for multiple inheritance. + * eval.c (evaluate_subexp [case OP_FUNCALL]): Simplify + virtual function calls by using value_virtual_fn_field(). + * values.c: New function baseclass_offset, derived from + baseclass_addr (which perhaps can be made obsolete?). + It returns an offset rather than an address. This is a + cleaner interface since it doesn't mess around allocating + new values. + * valops.c (search_struct_method): Use baseclass_offset + rather than baseclass_addr. + Mon Oct 5 16:02:04 1992 Stu Grossman (grossman at cygnus.com) * Makefile.in: Re-install 29K/UDI stuff. diff --git a/gdb/stabsread.c b/gdb/stabsread.c index 6bf29f4e9e2..532154ef107 100644 --- a/gdb/stabsread.c +++ b/gdb/stabsread.c @@ -1430,8 +1430,10 @@ read_struct_type (pp, type, objfile) p = *pp; if (*p == CPLUS_MARKER) { + if (*p == '_') /* GNU C++ anonymous type. */ + ; /* Special GNU C++ name. */ - if (*++p == 'v') + else if (*++p == 'v') { const char *prefix; char *name = 0; @@ -1470,15 +1472,12 @@ read_struct_type (pp, type, objfile) list->field.bitsize = 0; list->visibility = 0; /* private */ non_public_fields++; + + nfields++; + continue; } - /* GNU C++ anonymous type. */ - else if (*p == '_') - break; else complain (&invalid_cpp_abbrev_complaint, *pp); - - nfields++; - continue; } while (*p != ':') p++; diff --git a/gdb/values.c b/gdb/values.c index 8c299ccb25c..aaff412690f 100644 --- a/gdb/values.c +++ b/gdb/values.c @@ -903,12 +903,15 @@ value_field (arg1, fieldno) J is an index into F which provides the desired method. */ value -value_fn_field (f, j) +value_fn_field (arg1p, f, j, type, offset) + value *arg1p; struct fn_field *f; int j; + struct type *type; + int offset; { register value v; - register struct type *type = TYPE_FN_FIELD_TYPE (f, j); + register struct type *ftype = TYPE_FN_FIELD_TYPE (f, j); struct symbol *sym; sym = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j), @@ -916,27 +919,40 @@ value_fn_field (f, j) if (! sym) error ("Internal error: could not find physical method named %s", TYPE_FN_FIELD_PHYSNAME (f, j)); - v = allocate_value (type); + v = allocate_value (ftype); VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); - VALUE_TYPE (v) = type; + VALUE_TYPE (v) = ftype; + + if (arg1p) + { + if (type != VALUE_TYPE (*arg1p)) + *arg1p = value_ind (value_cast (lookup_pointer_type (type), + value_addr (*arg1p))); + + /* Move the `this' pointer according to the offset. */ + VALUE_OFFSET (*arg1p) += offset; + } + return v; } /* Return a virtual function as a value. ARG1 is the object which provides the virtual function - table pointer. ARG1 is side-effected in calling this function. + table pointer. *ARG1P is side-effected in calling this function. F is the list of member functions which contains the desired virtual function. J is an index into F which provides the desired virtual function. TYPE is the type in which F is located. */ value -value_virtual_fn_field (arg1, f, j, type) - value arg1; +value_virtual_fn_field (arg1p, f, j, type, offset) + value *arg1p; struct fn_field *f; int j; struct type *type; + int offset; { + value arg1 = *arg1p; /* First, get the virtual function table pointer. That comes with a strange type, so cast it to type `pointer to long' (which should serve just fine as a function type). Then, index into @@ -968,7 +984,9 @@ value_virtual_fn_field (arg1, f, j, type) /* The virtual function table is now an array of structures which have the form { int16 offset, delta; void *pfn; }. */ - vtbl = value_ind (value_field (arg1, TYPE_VPTR_FIELDNO (context))); + vtbl = value_ind (value_primitive_field (arg1, 0, + TYPE_VPTR_FIELDNO (context), + TYPE_VPTR_BASETYPE (context))); /* Index into the virtual function table. This is hard-coded because looking up a field is not cheap, and it may be important to save @@ -977,7 +995,7 @@ value_virtual_fn_field (arg1, f, j, type) entry = value_subscript (vtbl, vi); /* Move the `this' pointer according to the virtual function table. */ - VALUE_OFFSET (arg1) += value_as_long (value_field (entry, 0)); + VALUE_OFFSET (arg1) += value_as_long (value_field (entry, 0)) + offset; if (! VALUE_LAZY (arg1)) { VALUE_LAZY (arg1) = 1; @@ -988,6 +1006,7 @@ value_virtual_fn_field (arg1, f, j, type) /* Reinstantiate the function pointer with the correct type. */ VALUE_TYPE (vfn) = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)); + *arg1p = arg1; return vfn; } @@ -1103,6 +1122,67 @@ value_from_vtable_info (arg, type) return value_headof (arg, 0, type); } +/* Compute the offset of the baseclass which is + the INDEXth baseclass of class TYPE, for a value ARG, + wih extra offset of OFFSET. + The result is the offste of the baseclass value relative + to (the address of)(ARG) + OFFSET. + + -1 is returned on error. */ + +int +baseclass_offset (type, index, arg, offset) + struct type *type; + int index; + value arg; + int offset; +{ + struct type *basetype = TYPE_BASECLASS (type, index); + + if (BASETYPE_VIA_VIRTUAL (type, index)) + { + /* Must hunt for the pointer to this virtual baseclass. */ + register int i, len = TYPE_NFIELDS (type); + register int n_baseclasses = TYPE_N_BASECLASSES (type); + char *vbase_name, *type_name = type_name_no_tag (basetype); + + vbase_name = (char *)alloca (strlen (type_name) + 8); + sprintf (vbase_name, "_vb%c%s", CPLUS_MARKER, type_name); + /* First look for the virtual baseclass pointer + in the fields. */ + for (i = n_baseclasses; i < len; i++) + { + if (! strcmp (vbase_name, TYPE_FIELD_NAME (type, i))) + { + CORE_ADDR addr + = unpack_pointer (TYPE_FIELD_TYPE (type, i), + VALUE_CONTENTS (arg) + VALUE_OFFSET (arg) + + offset + + (TYPE_FIELD_BITPOS (type, i) / 8)); + + if (VALUE_LVAL (arg) != lval_memory) + return -1; + + return addr - + (LONGEST) (VALUE_ADDRESS (arg) + VALUE_OFFSET (arg) + offset); + } + } + /* Not in the fields, so try looking through the baseclasses. */ + for (i = index+1; i < n_baseclasses; i++) + { + int boffset = + baseclass_offset (type, i, arg, offset); + if (boffset) + return boffset; + } + /* Not found. */ + return -1; + } + + /* Baseclass is easily computed. */ + return TYPE_BASECLASS_BITPOS (type, index) / 8; +} + /* Compute the address of the baseclass which is the INDEXth baseclass of class TYPE. The TYPE base of the object is at VALADDR. @@ -1112,6 +1192,8 @@ value_from_vtable_info (arg, type) of the baseclasss, but the address which could not be read successfully. */ +/* FIXME Fix remaining uses of baseclass_addr to use baseclass_offset */ + char * baseclass_addr (type, index, valaddr, valuep, errp) struct type *type; -- 2.30.2