From: Per Bothner Date: Fri, 4 Sep 1992 07:37:18 +0000 (+0000) Subject: A ton of changes to improve C++ debugging. See ChangeLog. X-Git-Tag: gdb-4_18~21138 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=35fcebce93a949c589d0569e2b1111c1eb26bc2f;p=platform%2Fupstream%2Fbinutils.git A ton of changes to improve C++ debugging. See ChangeLog. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 9c0446f..d903e3d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,86 @@ +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, nested types are supported, and the calling + of inferiors methods is improved. + + * expression.h, c-exp.y: STRUCTOP_PTR and STRUCTOP_STRUCT + expression types now take an extra parameter that is used + for an (optional) type qualifier, as in: EXP.TYPE::NAME. + If there is no qualifier (as in EXP.NAME), the TYPE is NULL. + (Before, there was a cute but not-quote-valid re-write to + EXP.*(&TYPE::NAME .) + * parse.c (length_of_subexp, prefixify_subexp), expprint.c + (print_subexp), eval.c (evaluate_subexp): Handle the extra + operand of STRUCTOP_STRUCT and STRUCTOP_PTR. + + * 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. + + * gdbtypes.h: New macro TYPE_FIELD_NESTED. + * symtab.C, syntab.h: New function find_nested_type() + searches a class recursively for a nested type. + * c-exp.y: Support nested type syntax: TYPE1::TYPE2. + This required some nasty interactions between the lexer + and the parser (surprise, surprise), using the current_type + global variable (see comment above its declaration), + and the new function find_nested_type(). + * expprint.c (print_subexp), valprint.c (val_print_fields, + type_print_base [case TYPE_CODE_STRUCT]): Support nested types. + * stabsread.c (read_struct_type): Recognize types fields + nested in classes. + + * gdbtypes.c, symtab.h: New functions check_struct, + check_union, and check_enum (factored out from lookup_struct, + lookup_union, lookup_enum). + * c-exp.y: Support 'enum Foo::Bar' syntax as just the same + as 'Foo::Bar' followed by a call to check_enum. Similarly + for struct and union. + + * 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. + + * symfile.h: Declaration of set_demangling_style() moved + here from demangle.h (which is now in ../include). + * i386-xdep.c: Update comment. + * utils.c (strcmp_iw): Add a hack to allow "FOO(ARGS)" to + match "FOO". This allows 'break Foo' to work when Foo is + a mangled C++ function. (See comment before function.) + Thu Sep 3 09:17:05 1992 Stu Grossman (grossman at cygnus.com) * a68v-xdep.c (store_inferior_registers): Define as type void. diff --git a/gdb/c-exp.y b/gdb/c-exp.y index fa8ebb9..c49ad89 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -42,6 +42,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "symfile.h" #include "objfiles.h" +/* If current_type is non-NULL, it is a signal to the lexer that we have + just parsed: 'TYPE ::' and so if an identifier is seen, the lexer must + search for it in TYPE. This lex-time search is needed to parse + C++ nested types, as in: 'TYPE :: NESTED_TYPE', since this must + parse as a type, not a (non-type) identifier. */ + +static struct type *current_type = NULL; + /* These MUST be included in any grammar file!!!! Please choose unique names! Note that this are a combined list of variables that can be produced by any one of bison, byacc, or yacc. */ @@ -120,7 +128,7 @@ parse_number PARAMS ((char *, int, int, YYSTYPE *)); %} %type exp exp1 type_exp start variable qualified_name -%type type typebase +%type type typebase typebase_coloncolon qualified_type %type nonempty_typelist /* %type block */ @@ -144,6 +152,7 @@ parse_number PARAMS ((char *, int, int, YYSTYPE *)); %token STRING %token NAME /* BLOCKNAME defined below to give it higher precedence. */ %token TYPENAME +%token NESTED_TYPE %type name %type name_not_typename %type typename @@ -265,16 +274,16 @@ exp : SIZEOF exp %prec UNARY exp : exp ARROW name { write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_elt_type (NULL); write_exp_string ($3); write_exp_elt_opcode (STRUCTOP_PTR); } ; -exp : exp ARROW qualified_name - { /* exp->type::name becomes exp->*(&type::name) */ - /* Note: this doesn't work if name is a - static member! FIXME */ - write_exp_elt_opcode (UNOP_ADDR); - write_exp_elt_opcode (STRUCTOP_MPTR); } +exp : exp ARROW typebase_coloncolon name + { write_exp_elt_opcode (STRUCTOP_PTR); + write_exp_elt_type ($3); + write_exp_string ($4); + write_exp_elt_opcode (STRUCTOP_PTR); } ; exp : exp ARROW '*' exp { write_exp_elt_opcode (STRUCTOP_MPTR); } @@ -282,16 +291,16 @@ exp : exp ARROW '*' exp exp : exp '.' name { write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_elt_type (NULL); write_exp_string ($3); write_exp_elt_opcode (STRUCTOP_STRUCT); } ; -exp : exp '.' qualified_name - { /* exp.type::name becomes exp.*(&type::name) */ - /* Note: this doesn't work if name is a - static member! FIXME */ - write_exp_elt_opcode (UNOP_ADDR); - write_exp_elt_opcode (STRUCTOP_MEMBER); } +exp : exp '.' typebase_coloncolon name + { write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_elt_type ($3); + write_exp_string ($4); + write_exp_elt_opcode (STRUCTOP_STRUCT); } ; exp : exp '.' '*' exp @@ -576,7 +585,9 @@ variable: block COLONCOLON name write_exp_elt_opcode (OP_VAR_VALUE); } ; -qualified_name: typebase COLONCOLON name +typebase_coloncolon : typebase COLONCOLON { current_type = $1; $$ = $1; } + +qualified_name: typebase_coloncolon name { struct type *type = $1; if (TYPE_CODE (type) != TYPE_CODE_STRUCT @@ -586,10 +597,11 @@ qualified_name: typebase COLONCOLON name write_exp_elt_opcode (OP_SCOPE); write_exp_elt_type (type); - write_exp_string ($3); + write_exp_string ($2); write_exp_elt_opcode (OP_SCOPE); + current_type = NULL; } - | typebase COLONCOLON '~' name + | typebase_coloncolon '~' name { struct type *type = $1; struct stoken tmp_token; @@ -598,19 +610,20 @@ qualified_name: typebase COLONCOLON name error ("`%s' is not defined as an aggregate type.", TYPE_NAME (type)); - if (strcmp (type_name_no_tag (type), $4.ptr)) + if (strcmp (type_name_no_tag (type), $3.ptr)) error ("invalid destructor `%s::~%s'", - type_name_no_tag (type), $4.ptr); + type_name_no_tag (type), $3.ptr); - tmp_token.ptr = (char*) alloca ($4.length + 2); - tmp_token.length = $4.length + 1; + tmp_token.ptr = (char*) alloca ($3.length + 2); + tmp_token.length = $3.length + 1; tmp_token.ptr[0] = '~'; - memcpy (tmp_token.ptr+1, $4.ptr, $4.length); + memcpy (tmp_token.ptr+1, $3.ptr, $3.length); tmp_token.ptr[tmp_token.length] = 0; write_exp_elt_opcode (OP_SCOPE); write_exp_elt_type (type); write_exp_string (tmp_token); write_exp_elt_opcode (OP_SCOPE); + current_type = NULL; } ; @@ -822,9 +835,15 @@ func_mod: '(' ')' { free ((PTR)$2); $$ = 0; } ; +qualified_type: typebase_coloncolon NESTED_TYPE + { $$ = $2; current_type = NULL; } + ; + type : ptype - | typebase COLONCOLON '*' - { $$ = lookup_member_type (builtin_type_int, $1); } + | qualified_type + | typebase_coloncolon '*' + { $$ = lookup_member_type (builtin_type_int, $1); + current_type = NULL; } | type '(' typebase COLONCOLON '*' ')' { $$ = lookup_member_type ($1, $3); } | type '(' typebase COLONCOLON '*' ')' '(' ')' @@ -876,6 +895,10 @@ typebase | ENUM name { $$ = lookup_enum (copy_name ($2), expression_context_block); } + | STRUCT qualified_type { $$ = check_struct ($2); } + | CLASS qualified_type { $$ = check_struct ($2); } + | UNION qualified_type { $$ = check_union ($2); } + | ENUM qualified_type { $$ = check_enum ($2); } | UNSIGNED typename { $$ = lookup_unsigned_typename (TYPE_NAME($2.type)); } | UNSIGNED @@ -1419,6 +1442,17 @@ yylex () return VARIABLE; } + if (current_type) + { + struct type *t = + find_nested_type (current_type, copy_name (yylval.sval)); + if (t) + { + yylval.tval = t; + return NESTED_TYPE; + } + } + /* Use token-type BLOCKNAME for symbols that happen to be defined as functions or symtabs. If this is not so, then ... Use token-type TYPENAME for symbols that happen to be defined diff --git a/gdb/eval.c b/gdb/eval.c index 2b70c4b..55fca20 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -296,39 +296,34 @@ evaluate_subexp (expect_type, exp, pos, noside) arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); fnptr = longest_to_int (value_as_long (arg1)); - /* FIXME-tiemann: this is way obsolete. */ - if (fnptr < 128) + + if (METHOD_PTR_IS_VIRTUAL(fnptr)) { + int fnoffset = METHOD_PTR_TO_VOFFSET(fnptr); struct type *basetype; + struct type *domain_type = + TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))); int i, j; basetype = TYPE_TARGET_TYPE (VALUE_TYPE (arg2)); - basetype = TYPE_VPTR_BASETYPE (basetype); + if (domain_type != basetype) + arg2 = value_cast(lookup_pointer_type (domain_type), arg2); + basetype = TYPE_VPTR_BASETYPE (domain_type); for (i = TYPE_NFN_FIELDS (basetype) - 1; i >= 0; i--) { struct fn_field *f = TYPE_FN_FIELDLIST1 (basetype, i); /* If one is virtual, then all are virtual. */ if (TYPE_FN_FIELD_VIRTUAL_P (f, 0)) for (j = TYPE_FN_FIELDLIST_LENGTH (basetype, i) - 1; j >= 0; --j) - if (TYPE_FN_FIELD_VOFFSET (f, j) == fnptr) + if (TYPE_FN_FIELD_VOFFSET (f, j) == fnoffset) { - value vtbl; - value base = value_ind (arg2); - struct type *fntype = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)); - - if (TYPE_VPTR_FIELDNO (basetype) < 0) - fill_in_vptr_fieldno (basetype); - - VALUE_TYPE (base) = basetype; - vtbl = value_field (base, TYPE_VPTR_FIELDNO (basetype)); - VALUE_TYPE (vtbl) = lookup_pointer_type (fntype); - VALUE_TYPE (arg1) = builtin_type_int; - arg1 = value_subscript (vtbl, arg1); - VALUE_TYPE (arg1) = fntype; + value temp = value_ind (arg2); + arg1 = value_virtual_fn_field (&temp, f, j, domain_type, 0); + arg2 = value_addr (temp); goto got_it; } } if (i < 0) - error ("virtual function at index %d not found", fnptr); + error ("virtual function at index %d not found", fnoffset); } else { @@ -347,8 +342,9 @@ evaluate_subexp (expect_type, exp, pos, noside) nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1; /* First, evaluate the structure into arg2 */ pc2 = (*pos)++; - tem2 = strlen (&exp->elts[pc2 + 1].string); - *pos += 2 + (tem2 + sizeof (union exp_element)) / sizeof (union exp_element); + /* type = exp->elts[pc2 + 1].type; */ + tem2 = strlen (&exp->elts[pc2 + 2].string); + *pos += 3 + (tem2 + sizeof (union exp_element)) / sizeof (union exp_element); if (noside == EVAL_SKIP) goto nosideret; @@ -381,9 +377,13 @@ evaluate_subexp (expect_type, exp, pos, noside) int static_memfuncp; value temp = arg2; + /* argvec[0] gets the method; + argvec[1] gets the 'this' pointer (unless static) (from arg2); + the remaining args go into the rest of argvec. */ + argvec[1] = arg2; argvec[0] = - value_struct_elt (&temp, argvec+1, &exp->elts[pc2 + 1].string, + value_struct_elt (&temp, argvec+1, &exp->elts[pc2 + 2].string, &static_memfuncp, op == STRUCTOP_STRUCT ? "structure" : "structure pointer"); @@ -428,40 +428,50 @@ evaluate_subexp (expect_type, exp, pos, noside) return call_function_by_hand (argvec[0], nargs, argvec + 1); case STRUCTOP_STRUCT: - tem = strlen (&exp->elts[pc + 1].string); - (*pos) += 2 + ((tem + sizeof (union exp_element)) + tem = strlen (&exp->elts[pc + 2].string); + (*pos) += 3 + ((tem + sizeof (union exp_element)) / sizeof (union exp_element)); arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR) + goto handle_structop_ptr; + type = exp->elts[pc + 1].type; + if (type) + arg1 = value_ind (value_cast (lookup_pointer_type (type), + value_addr (arg1))); if (noside == EVAL_SKIP) goto nosideret; if (noside == EVAL_AVOID_SIDE_EFFECTS) return value_zero (lookup_struct_elt_type (VALUE_TYPE (arg1), - &exp->elts[pc + 1].string, - 1), + &exp->elts[pc + 2].string, + 0), lval_memory); else { value temp = arg1; - return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 1].string, + return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 2].string, (int *) 0, "structure"); } case STRUCTOP_PTR: - tem = strlen (&exp->elts[pc + 1].string); - (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); + tem = strlen (&exp->elts[pc + 2].string); + (*pos) += 3 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside); + handle_structop_ptr: + type = exp->elts[pc + 1].type; + if (type) + arg1 = value_cast (lookup_pointer_type (type), arg1); if (noside == EVAL_SKIP) goto nosideret; if (noside == EVAL_AVOID_SIDE_EFFECTS) return value_zero (lookup_struct_elt_type (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)), - &exp->elts[pc + 1].string, - 1), + &exp->elts[pc + 2].string, + 0), lval_memory); else { value temp = arg1; - return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 1].string, + return value_struct_elt (&temp, (value *)0, &exp->elts[pc + 2].string, (int *) 0, "structure pointer"); } @@ -564,8 +574,18 @@ evaluate_subexp (expect_type, exp, pos, noside) if (noside == EVAL_SKIP) goto nosideret; if (noside == EVAL_AVOID_SIDE_EFFECTS) - return value_zero (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)), - VALUE_LVAL (arg1)); + { + /* If the user attempts to subscript something that has no target + type (like a plain int variable for example), then report this + as an error. */ + + type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1)); + if (type) + return value_zero (type, VALUE_LVAL (arg1)); + else + error ("cannot subscript something of type `%s'", + TYPE_NAME (VALUE_TYPE (arg1))); + } if (binop_user_defined_p (op, arg1, arg2)) return value_x_binop (arg1, arg2, op, OP_NULL); @@ -1068,7 +1088,7 @@ parse_and_eval_type (p, length) char *tmp = (char *)alloca (length + 4); struct expression *expr; tmp[0] = '('; - (void) memcpy (tmp+1, p, length); + memcpy (tmp+1, p, length); tmp[length+1] = ')'; tmp[length+2] = '0'; tmp[length+3] = '\0'; diff --git a/gdb/expprint.c b/gdb/expprint.c index f642ea7..357c890 100644 --- a/gdb/expprint.c +++ b/gdb/expprint.c @@ -74,12 +74,9 @@ print_subexp (exp, pos, stream, prec) /* Common ops */ case OP_SCOPE: - myprec = PREC_PREFIX; - assoc = 0; (*pos) += 2; - print_subexp (exp, pos, stream, - (enum precedence) ((int) myprec + assoc)); - fputs_filtered (" :: ", stream); + type_print (exp->elts[pc + 1].type, "", stream, 0); + fputs_filtered ("::", stream); nargs = strlen (&exp->elts[pc + 2].string); (*pos) += 1 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element); @@ -114,7 +111,7 @@ print_subexp (exp, pos, stream, prec) case OP_REGISTER: (*pos) += 2; fprintf_filtered (stream, "$%s", - reg_names[longest_to_int (exp->elts[pc + 1].longconst)); + reg_names[longest_to_int (exp->elts[pc + 1].longconst)]); return; case OP_INTERNALVAR: @@ -163,20 +160,30 @@ print_subexp (exp, pos, stream, prec) return; case STRUCTOP_STRUCT: - tem = strlen (&exp->elts[pc + 1].string); - (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); + tem = strlen (&exp->elts[pc + 2].string); + (*pos) += 3 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); print_subexp (exp, pos, stream, PREC_SUFFIX); fputs_filtered (".", stream); - fputs_filtered (&exp->elts[pc + 1].string, stream); + if (exp->elts[pc + 1].type) + { + type_print (exp->elts[pc + 1].type, "", stream, 0); + fputs_filtered ("::", stream); + } + fputs_filtered (&exp->elts[pc + 2].string, stream); return; /* Will not occur for Modula-2 */ case STRUCTOP_PTR: - tem = strlen (&exp->elts[pc + 1].string); - (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); + tem = strlen (&exp->elts[pc + 2].string); + (*pos) += 3 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); print_subexp (exp, pos, stream, PREC_SUFFIX); fputs_filtered ("->", stream); - fputs_filtered (&exp->elts[pc + 1].string, stream); + if (exp->elts[pc + 1].type) + { + type_print (exp->elts[pc + 1].type, "", stream, 0); + fputs_filtered ("::", stream); + } + fputs_filtered (&exp->elts[pc + 2].string, stream); return; case BINOP_SUBSCRIPT: diff --git a/gdb/expression.h b/gdb/expression.h index b7a6fff..0ef5c4d 100644 --- a/gdb/expression.h +++ b/gdb/expression.h @@ -1,21 +1,24 @@ /* Definitions for expressions stored in reversed prefix form, for GDB. - Copyright (C) 1986, 1989 Free Software Foundation, Inc. + Copyright 1986, 1989, 1992 Free Software Foundation, Inc. This file is part of GDB. -GDB is free software; you can redistribute it and/or modify +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 1, or (at your option) -any later version. +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. -GDB is distributed in the hope that it will be useful, +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 GDB; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if !defined (EXPRESSION_H) +#define EXPRESSION_H 1 /* Definitions for saved C expressions. */ @@ -34,6 +37,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ enum exp_opcode { + /* Used when it's necessary to pass an opcode which will be ignored, + or to catch uninitialized values. */ + OP_NULL, + /* BINOP_... operate on two values computed by following subexpressions, replacing them by one result value. They take no immediate arguments. */ BINOP_ADD, /* + */ @@ -58,6 +65,7 @@ enum exp_opcode BINOP_ASSIGN, /* = */ BINOP_COMMA, /* , */ BINOP_SUBSCRIPT, /* x[y] */ + BINOP_MULTI_SUBSCRIPT, /* Modula-2 x[a,b,...] */ BINOP_EXP, /* Exponentiation */ /* C++. */ @@ -73,7 +81,8 @@ enum exp_opcode STRUCTOP_MPTR, /* end of C++. */ - BINOP_END, + /* For Modula-2 integer division DIV */ + BINOP_INTDIV, BINOP_ASSIGN_MODIFY, /* +=, -=, *=, and so on. The following exp_element is another opcode, @@ -81,6 +90,14 @@ enum exp_opcode Then comes another BINOP_ASSIGN_MODIFY, making three exp_elements in total. */ + /* Modula-2 standard (binary) procedures*/ + BINOP_VAL, + BINOP_INCL, + BINOP_EXCL, + + /* This must be the highest BINOP_ value, for expprint.c. */ + BINOP_END, + /* Operates on three values computed by following subexpressions. */ TERNOP_COND, /* ?: */ @@ -146,6 +163,22 @@ enum exp_opcode UNOP_POSTDECREMENT, /* -- after an expression */ UNOP_SIZEOF, /* Unary sizeof (followed by expression) */ + UNOP_PLUS, /* Unary plus */ + + UNOP_CAP, /* Modula-2 standard (unary) procedures */ + UNOP_CHR, + UNOP_ORD, + UNOP_ABS, + UNOP_FLOAT, + UNOP_HIGH, + UNOP_MAX, + UNOP_MIN, + UNOP_ODD, + UNOP_TRUNC, + + OP_BOOL, /* Modula-2 builtin BOOLEAN type */ + OP_M2_STRING, /* Modula-2 string constants */ + /* STRUCTOP_... operate on a value from a following subexpression by extracting a structure component specified by a string that appears in the following exp_elements (as many as needed). @@ -153,6 +186,11 @@ enum exp_opcode They differ only in the error message given in case the value is not suitable or the structure component specified is not found. + After the sub-expression and before the string is a (struct type*). + This is normally NULL, but is used for the TYPE in a C++ qualified + reference like EXP.TYPE::NAME. (EXP.TYPE1::TYPE2::NAME does + not work, unfortunately.) + The length of the string follows in the next exp_element, (after the string), followed by another STRUCTOP_... code. */ STRUCTOP_STRUCT, @@ -168,6 +206,10 @@ enum exp_opcode a string, which, of course, is variable length. */ OP_SCOPE, + /* OP_TYPE is for parsing types, and used with the "ptype" command + so we can look up types that are qualified by scope, either with + the GDB "::" operator, or the Modula-2 '.' operator. */ + OP_TYPE }; union exp_element @@ -183,18 +225,30 @@ union exp_element struct expression { + const struct language_defn *language_defn; /* language it was entered in */ int nelts; union exp_element elts[1]; }; -/* From expread.y. */ -struct expression *parse_c_expression (); -struct expression *parse_c_1 (); +/* From parse.c */ + +extern struct expression * +parse_expression PARAMS ((char *)); + +extern struct expression * +parse_exp_1 PARAMS ((char **, struct block *, int)); /* The innermost context required by the stack and register variables we've encountered so far. To use this, set it to NULL, then call - parse_c_, then look at it. */ + parse_, then look at it. */ extern struct block *innermost_block; -/* From expprint.c. */ -void print_expression (); +/* From expprint.c */ + +extern void +print_expression PARAMS ((struct expression *, FILE *)); + +extern char * +op_string PARAMS ((enum exp_opcode)); + +#endif /* !defined (EXPRESSION_H) */ diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 2090eda..820925b 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -513,6 +513,15 @@ lookup_signed_typename (name) return lookup_typename (name, (struct block *) NULL, 0); } +struct type * +check_struct (type) + struct type *type; +{ + if (TYPE_CODE (type) != TYPE_CODE_STRUCT) + error ("This context has %s, not a struct or class.", TYPE_NAME (type)); + return type; +} + /* Lookup a structure type named "struct NAME", visible in lexical block BLOCK. */ @@ -530,11 +539,16 @@ lookup_struct (name, block) { error ("No struct type named %s.", name); } - if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT) - { - error ("This context has class, union or enum %s, not a struct.", name); - } - return (SYMBOL_TYPE (sym)); + return check_struct (SYMBOL_TYPE (sym)); +} + +struct type * +check_union (type) + struct type *type; +{ + if (TYPE_CODE (type) != TYPE_CODE_UNION) + error ("This context has %s, not a union.", TYPE_NAME (type)); + return type; } /* Lookup a union type named "union NAME", @@ -554,11 +568,16 @@ lookup_union (name, block) { error ("No union type named %s.", name); } - if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_UNION) - { - error ("This context has class, struct or enum %s, not a union.", name); - } - return (SYMBOL_TYPE (sym)); + return check_union (SYMBOL_TYPE (sym)); +} + +struct type * +check_enum (type) + struct type *type; +{ + if (TYPE_CODE (type) != TYPE_CODE_ENUM) + error ("This context has %s, not an enum.", TYPE_NAME (type)); + return type; } /* Lookup an enum type named "enum NAME", @@ -577,11 +596,7 @@ lookup_enum (name, block) { error ("No enum type named %s.", name); } - if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_ENUM) - { - error ("This context has class, struct or union %s, not an enum.", name); - } - return (SYMBOL_TYPE (sym)); + return check_enum (SYMBOL_TYPE (sym)); } /* Lookup a template type named "template NAME", diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 95f4035..b7b9917 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -435,6 +435,7 @@ allocate_cplus_struct_type PARAMS ((struct type *)); B_TST(TYPE_CPLUS_SPECIFIC(thistype)->virtual_field_bits, (n)) #define TYPE_FIELD_STATIC(thistype, n) ((thistype)->fields[n].bitpos == -1) +#define TYPE_FIELD_NESTED(thistype, n) ((thistype)->fields[n].bitpos == -2) #define TYPE_FIELD_STATIC_PHYSNAME(thistype, n) ((char *)(thistype)->fields[n].bitsize) #define TYPE_FN_FIELDLISTS(thistype) TYPE_CPLUS_SPECIFIC(thistype)->fn_fieldlists diff --git a/gdb/i386-xdep.c b/gdb/i386-xdep.c index 38ba8f0..67e904b 100644 --- a/gdb/i386-xdep.c +++ b/gdb/i386-xdep.c @@ -44,7 +44,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ extern struct ext_format ext_format_i387; -/* this table must line up with REGISTER_NAMES in m-i386.h */ +/* this table must line up with REGISTER_NAMES in tm-i386v.h */ /* symbols like 'EAX' come from */ static int regmap[] = { diff --git a/gdb/parse.c b/gdb/parse.c index 4090302..5cfad97 100644 --- a/gdb/parse.c +++ b/gdb/parse.c @@ -275,6 +275,9 @@ length_of_subexp (expr, endpos) switch (i) { + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; /* C++ */ case OP_SCOPE: oplen = 4 + ((expr->elts[endpos - 2].longconst @@ -326,9 +329,6 @@ length_of_subexp (expr, endpos) args = 1; break; - case STRUCTOP_STRUCT: - case STRUCTOP_PTR: - args = 1; case OP_M2_STRING: case OP_STRING: oplen = 3 + ((expr->elts[endpos - 2].longconst @@ -393,6 +393,9 @@ prefixify_subexp (inexpr, outexpr, inend, outbeg) opcode = inexpr->elts[inend - 1].opcode; switch (opcode) { + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; /* C++ */ case OP_SCOPE: oplen = 4 + ((inexpr->elts[inend - 2].longconst @@ -443,9 +446,6 @@ prefixify_subexp (inexpr, outexpr, inend, outbeg) args=1; break; - case STRUCTOP_STRUCT: - case STRUCTOP_PTR: - args = 1; case OP_M2_STRING: case OP_STRING: oplen = 3 + ((inexpr->elts[inend - 2].longconst diff --git a/gdb/stabsread.c b/gdb/stabsread.c index 832d9c3..06b61ec 100644 --- a/gdb/stabsread.c +++ b/gdb/stabsread.c @@ -1158,7 +1158,8 @@ read_type (pp, objfile) case '#': /* Method (class & fn) type */ if ((*pp)[0] == '#') { - /* We'll get the parameter types from the name. */ + /* This "minimized" format bogus, because it doesn't yield + enough information. I've changed gcc to not emit it. --Per */ struct type *return_type; *pp += 1; @@ -1417,8 +1418,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; @@ -1457,15 +1460,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++; @@ -1508,21 +1508,26 @@ read_struct_type (pp, type, objfile) if (**pp == ':') { p = ++(*pp); -#if 0 - /* Possible future hook for nested types. */ if (**pp == '!') - { - list->field.bitpos = (long)-2; /* nested type */ + { /* C++ nested type -as in FOO::BAR */ + list->field.bitpos = (long)(-2); /* nested type */ p = ++(*pp); + if (TYPE_NAME (list->field.type) == NULL && **pp == '\'') + { + for (p = ++(*pp); *p != '\''; ) p++; + TYPE_NAME (list->field.type) = savestring (*pp, p - *pp); + } + while (*p != ';') p++; + list->field.bitsize = 0; + *pp = p + 1; } else -#endif { /* Static class member. */ - list->field.bitpos = (long)-1; + list->field.bitpos = (long)(-1); + while (*p != ';') p++; + list->field.bitsize = (long) savestring (*pp, p - *pp); + *pp = p + 1; } - while (*p != ';') p++; - list->field.bitsize = (long) savestring (*pp, p - *pp); - *pp = p + 1; nfields++; continue; } diff --git a/gdb/symtab.c b/gdb/symtab.c index a0033d9..cb97621 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -186,7 +186,8 @@ lookup_symtab_1 (name) got_psymtab: if (ps -> readin) - error ("Internal: readin pst for `%s' found when no symtab found.", name); + error ("Internal: readin %s pst for `%s' found when no symtab found.", + ps -> filename, name); s = PSYMTAB_TO_SYMTAB (ps); @@ -262,13 +263,56 @@ gdb_mangle_name (type, i, j) struct fn_field *method = &f[j]; char *field_name = TYPE_FN_FIELDLIST_NAME (type, i); char *physname = TYPE_FN_FIELD_PHYSNAME (f, j); - char *opname; - int is_constructor = strcmp (field_name, type_name_no_tag (type)) == 0; - + char *newname = type_name_no_tag (type); + int is_constructor = strcmp(field_name, newname) == 0; + int is_destructor = is_constructor && physname[0] == '_' + && physname[1] == CPLUS_MARKER && physname[2] == '_'; /* Need a new type prefix. */ char *const_prefix = method->is_const ? "C" : ""; char *volatile_prefix = method->is_volatile ? "V" : ""; char buf[20]; +#ifndef GCC_MANGLE_BUG + int len = strlen (newname); + + if (is_destructor) + { + mangled_name = (char*) xmalloc(strlen(physname)+1); + strcpy(mangled_name, physname); + return mangled_name; + } + + sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len); + mangled_name_len = ((is_constructor ? 0 : strlen (field_name)) + + strlen (buf) + len + + strlen (physname) + + 1); + + /* Only needed for GNU-mangled names. ANSI-mangled names + work with the normal mechanisms. */ + if (OPNAME_PREFIX_P (field_name)) + { + char *opname = cplus_mangle_opname (field_name + 3, 0); + if (opname == NULL) + error ("No mangling for \"%s\"", field_name); + mangled_name_len += strlen (opname); + mangled_name = (char *)xmalloc (mangled_name_len); + + strncpy (mangled_name, field_name, 3); + mangled_name[3] = '\0'; + strcat (mangled_name, opname); + } + else + { + mangled_name = (char *)xmalloc (mangled_name_len); + if (is_constructor) + mangled_name[0] = '\0'; + else + strcpy (mangled_name, field_name); + } + strcat (mangled_name, buf); + strcat (mangled_name, newname); +#else + char *opname; if (is_constructor) { @@ -310,8 +354,9 @@ gdb_mangle_name (type, i, j) } } strcat (mangled_name, buf); - strcat (mangled_name, physname); +#endif + strcat (mangled_name, physname); return (mangled_name); } @@ -521,7 +566,8 @@ found: ALL_MSYMBOLS (objfile, msymbol) { - demangled = demangle_and_match (msymbol -> name, name, 0); + demangled = demangle_and_match (msymbol -> name, name, + DMGL_PARAMS | DMGL_ANSI); if (demangled != NULL) { free (demangled); @@ -579,7 +625,7 @@ found_msym: block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK); sym = lookup_block_symbol (block, name, namespace); if (!sym) - error ("Internal: global symbol `%s' found in psymtab but not in symtab", name); + error ("Internal: global symbol `%s' found in %s psymtab but not in symtab", name, ps->filename); if (symtab != NULL) *symtab = s; return sym; @@ -613,7 +659,7 @@ found_msym: block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); sym = lookup_block_symbol (block, name, namespace); if (!sym) - error ("Internal: static symbol `%s' found in psymtab but not in symtab", name); + error ("Internal: static symbol `%s' found in %s psymtab but not in symtab", name, ps->filename); if (symtab != NULL) *symtab = s; return sym; @@ -648,7 +694,7 @@ found_msym: block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK); sym = lookup_demangled_block_symbol (block, name); if (!sym) - error ("Internal: mangled static symbol `%s' found in psymtab but not in symtab", name); + error ("Internal: mangled static symbol `%s' found in %s psymtab but not in symtab", name, ps->filename); if (symtab != NULL) *symtab = s; return sym; @@ -680,7 +726,8 @@ lookup_demangled_block_symbol (block, name) sym = BLOCK_SYM (block, bot); if (SYMBOL_NAMESPACE (sym) == VAR_NAMESPACE) { - demangled = demangle_and_match (SYMBOL_NAME (sym), name, 0); + demangled = demangle_and_match (SYMBOL_NAME (sym), name, + DMGL_PARAMS | DMGL_ANSI); if (demangled != NULL) { free (demangled); @@ -712,7 +759,8 @@ lookup_demangled_partial_symbol (pst, name) { if (SYMBOL_NAMESPACE (psym) == VAR_NAMESPACE) { - demangled = demangle_and_match (SYMBOL_NAME (psym), name, 0); + demangled = demangle_and_match (SYMBOL_NAME (psym), name, + DMGL_PARAMS | DMGL_ANSI); if (demangled != NULL) { free (demangled); @@ -1221,6 +1269,31 @@ find_pc_line_pc_range (pc, startptr, endptr) return sal.symtab != 0; } +struct type * +find_nested_type (type, name) + struct type *type; + char *name; +{ + int i; + for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--) + { + char *t_field_name = TYPE_FIELD_NAME (type, i); + + if (t_field_name && !strcmp (t_field_name, name)) + if (TYPE_FIELD_NESTED (type, i)) + { + return TYPE_FIELD_TYPE (type, i); + } + } + for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) + { + struct type * t = find_nested_type (TYPE_BASECLASS (type, i), name); + if (t) + return t; + } + return NULL; +} + /* If P is of the form "operator[ \t]+..." where `...' is some legitimate operator text, return a pointer to the beginning of the substring of the operator text. diff --git a/gdb/symtab.h b/gdb/symtab.h index 6b9c402..dae1e61 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -562,6 +562,15 @@ lookup_union PARAMS ((char *, struct block *)); extern struct type * lookup_enum PARAMS ((char *, struct block *)); +extern struct type * +check_struct PARAMS ((struct type *)); + +extern struct type * +check_union PARAMS ((struct type *)); + +extern struct type * +check_enum PARAMS ((struct type *)); + extern struct symbol * block_function PARAMS ((struct block *)); @@ -668,6 +677,22 @@ decode_line_1 PARAMS ((char **, int, struct symtab *, int)); /* Symmisc.c */ +#if MAINTENANCE_CMDS + +void +maintenance_print_symbols PARAMS ((char *, int)); + +void +maintenance_print_psymbols PARAMS ((char *, int)); + +void +maintenance_print_msymbols PARAMS ((char *, int)); + +void +maintenance_print_objfiles PARAMS ((char *, int)); + +#endif + extern void free_symtab PARAMS ((struct symtab *)); @@ -707,6 +732,9 @@ clear_symtab_users_once PARAMS ((void)); extern struct partial_symtab * find_main_psymtab PARAMS ((void)); +extern struct type * +find_nested_type PARAMS ((struct type *, char*)); + /* blockframe.c */ extern struct blockvector * diff --git a/gdb/valops.c b/gdb/valops.c index a852cfb..791b097 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -43,7 +43,7 @@ static value search_struct_field PARAMS ((char *, value, int, struct type *, int)); static value -search_struct_method PARAMS ((char *, value, value *, int, int *, +search_struct_method PARAMS ((char *, value *, value *, int, int *, struct type *)); static int @@ -1038,6 +1038,7 @@ search_struct_field (name, arg1, offset, type, looking_for_baseclass) if (BASETYPE_VIA_VIRTUAL (type, i)) { value v2; + /* Fix to use baseclass_offset instead. FIXME */ baseclass_addr (type, i, VALUE_CONTENTS (arg1) + offset, &v2, (int *)NULL); if (v2 == 0) @@ -1065,9 +1066,9 @@ search_struct_field (name, arg1, offset, type, looking_for_baseclass) If found, return value, else return NULL. */ static value -search_struct_method (name, arg1, args, offset, static_memfuncp, type) +search_struct_method (name, arg1p, args, offset, static_memfuncp, type) char *name; - register value arg1, *args; + register value *arg1p, *args; int offset, *static_memfuncp; register struct type *type; { @@ -1092,10 +1093,10 @@ search_struct_method (name, arg1, args, offset, static_memfuncp, type) TYPE_FN_FIELD_ARGS (f, j), args)) { if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) - return (value)value_virtual_fn_field (arg1, f, j, type); + return (value)value_virtual_fn_field (arg1p, f, j, type, offset); if (TYPE_FN_FIELD_STATIC_P (f, j) && static_memfuncp) *static_memfuncp = 1; - return (value)value_fn_field (f, j); + return (value)value_fn_field (arg1p, f, j, type, offset); } j--; } @@ -1104,25 +1105,27 @@ search_struct_method (name, arg1, args, offset, static_memfuncp, type) for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) { - value v, v2; + value v; int base_offset; if (BASETYPE_VIA_VIRTUAL (type, i)) { - baseclass_addr (type, i, VALUE_CONTENTS (arg1) + offset, - &v2, (int *)NULL); - if (v2 == 0) + base_offset = + baseclass_offset (type, i, *arg1p, offset); + if (base_offset == -1) error ("virtual baseclass botch"); - base_offset = 0; } else { - v2 = arg1; base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8; } - v = search_struct_method (name, v2, args, base_offset, + v = search_struct_method (name, arg1p, args, base_offset + offset, static_memfuncp, TYPE_BASECLASS (type, i)); - if (v) return v; + if (v) + { +/* *arg1p = arg1_tmp;*/ + return v; + } } return NULL; } @@ -1193,7 +1196,7 @@ value_struct_elt (argp, args, name, static_memfuncp, err) if (destructor_name_p (name, t)) error ("Cannot get value of destructor"); - v = search_struct_method (name, *argp, args, 0, static_memfuncp, t); + v = search_struct_method (name, argp, args, 0, static_memfuncp, t); if (v == 0) { @@ -1210,8 +1213,9 @@ value_struct_elt (argp, args, name, static_memfuncp, err) if (!args[1]) { /* destructors are a special case. */ - return (value)value_fn_field (TYPE_FN_FIELDLIST1 (t, 0), - TYPE_FN_FIELDLIST_LENGTH (t, 0)); + return (value)value_fn_field (NULL, TYPE_FN_FIELDLIST1 (t, 0), + TYPE_FN_FIELDLIST_LENGTH (t, 0), + 0, 0); } else { @@ -1219,7 +1223,7 @@ value_struct_elt (argp, args, name, static_memfuncp, err) } } else - v = search_struct_method (name, *argp, args, 0, static_memfuncp, t); + v = search_struct_method (name, argp, args, 0, static_memfuncp, t); if (v == 0) { @@ -1414,23 +1418,29 @@ value_struct_elt_for_reference (domain, offset, curtype, name, intype) (lookup_reference_type (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j), domain)), - (LONGEST) TYPE_FN_FIELD_VOFFSET (f, j)); + METHOD_PTR_FROM_VOFFSET((LONGEST) TYPE_FN_FIELD_VOFFSET (f, j))); } else { struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j), 0, VAR_NAMESPACE, 0, NULL); - v = read_var_value (s, 0); + if (s == NULL) + { + v = 0; + } + else + { + v = read_var_value (s, 0); #if 0 - VALUE_TYPE (v) = lookup_reference_type - (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j), - domain)); + VALUE_TYPE (v) = lookup_reference_type + (lookup_member_type (TYPE_FN_FIELD_TYPE (f, j), + domain)); #endif - return v; } + return v; } } - + } for (i = TYPE_N_BASECLASSES (t) - 1; i >= 0; i--) { value v; diff --git a/gdb/valprint.c b/gdb/valprint.c index ac1611f..db6f7fc 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -510,7 +510,7 @@ val_print_fields (type, valaddr, stream, format, recurse, pretty, dont_print) for (i = n_baseclasses; i < len; i++) { /* Check if static field */ - if (TYPE_FIELD_STATIC (type, i)) + if (TYPE_FIELD_STATIC (type, i) || TYPE_FIELD_NESTED (type, i)) continue; if (fields_seen) fprintf_filtered (stream, ", "); @@ -628,6 +628,7 @@ cplus_val_print (type, valaddr, stream, format, recurse, pretty, dont_print) obstack_ptr_grow (&dont_print_obstack, TYPE_BASECLASS (type, i)); } + /* Fix to use baseclass_offset instead. FIXME */ baddr = baseclass_addr (type, i, valaddr, 0, &err); if (err == 0 && baddr == 0) error ("could not find virtual baseclass `%s'\n", @@ -867,8 +868,9 @@ val_print (type, valaddr, address, stream, format, deref_ref, recurse, pretty) addr = unpack_pointer (lookup_pointer_type (builtin_type_void), valaddr); - if (addr < 128) /* FIXME! What is this 128? */ + if (METHOD_PTR_IS_VIRTUAL(addr)) { + int offset = METHOD_PTR_TO_VOFFSET(addr); len = TYPE_NFN_FIELDS (domain); for (i = 0; i < len; i++) { @@ -878,9 +880,9 @@ val_print (type, valaddr, address, stream, format, deref_ref, recurse, pretty) for (j = 0; j < len2; j++) { QUIT; - if (TYPE_FN_FIELD_VOFFSET (f, j) == addr) + if (TYPE_FN_FIELD_VOFFSET (f, j) == offset) { - kind = "virtual"; + kind = "virtual "; goto common; } } @@ -1473,7 +1475,11 @@ type_print_derivation_info (stream, type) BASETYPE_VIA_PUBLIC (type, i) ? "public" : "private", BASETYPE_VIA_VIRTUAL(type, i) ? " virtual" : ""); name = type_name_no_tag (TYPE_BASECLASS (type, i)); - fprintf_filtered (stream, "%s ", name ? name : "(null)"); + fprintf_filtered (stream, "%s", name ? name : "(null)"); + } + if (i > 0) + { + fputs_filtered (" ", stream); } } @@ -1841,10 +1847,14 @@ type_print_base (type, stream, show, level) { fprintf_filtered (stream, "static "); } + if (TYPE_FIELD_NESTED (type, i)) + { + fprintf_filtered (stream, "typedef "); + } type_print_1 (TYPE_FIELD_TYPE (type, i), TYPE_FIELD_NAME (type, i), stream, show - 1, level + 4); - if (!TYPE_FIELD_STATIC (type, i) + if (!TYPE_FIELD_STATIC (type, i) && !TYPE_FIELD_NESTED (type, i) && TYPE_FIELD_PACKED (type, i)) { /* It is a bitfield. This code does not attempt @@ -1858,8 +1868,13 @@ type_print_base (type, stream, show, level) fprintf_filtered (stream, ";\n"); } - /* C++: print out the methods */ + /* If there are both fields and methods, put a space between. */ len = TYPE_NFN_FIELDS (type); + if (len && section_type != s_none) + fprintf_filtered (stream, "\n"); + + /* C++: print out the methods */ + for (i = 0; i < len; i++) { struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i); diff --git a/gdb/value.h b/gdb/value.h index 7333578..43408a9 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -52,7 +52,7 @@ struct value { /* Address in inferior or byte of registers structure. */ CORE_ADDR address; - /* Pointer to interrnal variable. */ + /* Pointer to internal variable. */ struct internalvar *internalvar; /* Number of register. Only used with lval_reg_frame_relative. */ @@ -62,7 +62,9 @@ struct value int offset; /* Only used for bitfields; number of bits contained in them. */ int bitsize; - /* Only used for bitfields; position of start of field. */ + /* Only used for bitfields; position of start of field. + For BITS_BIG_ENDIAN=0 targets, it is the position of the LSB. + For BITS_BIG_ENDIAN=1 targets, it is the position of the MSB. */ int bitpos; /* Frame value is relative to. In practice, this address is only used if the value is stored in several registers in other than @@ -182,6 +184,12 @@ struct internalvar value value; }; +/* Pointer to member function. Depends on compiler implementation. */ + +#define METHOD_PTR_IS_VIRTUAL(ADDR) ((ADDR) & 0x80000000) +#define METHOD_PTR_FROM_VOFFSET(OFFSET) (0x80000000 + (OFFSET)) +#define METHOD_PTR_TO_VOFFSET(ADDR) (~0x80000000 & (ADDR)) + #include "symtab.h" #include "gdbtypes.h" @@ -212,7 +220,7 @@ unpack_double PARAMS ((struct type *type, char *valaddr, int *invp)); extern CORE_ADDR unpack_pointer PARAMS ((struct type *type, char *valaddr)); -extern long +extern LONGEST unpack_field_as_long PARAMS ((struct type *type, char *valaddr, int fieldno)); @@ -298,6 +306,7 @@ value_struct_elt PARAMS ((value *argp, value *args, char *name, extern value value_struct_elt_for_reference PARAMS ((struct type *domain, + int offset, struct type *curtype, char *name, struct type *intype)); @@ -396,11 +405,12 @@ extern value value_x_unop PARAMS ((value arg1, enum exp_opcode op)); extern value -value_fn_field PARAMS ((struct fn_field *f, int j)); +value_fn_field PARAMS ((value *arg1p, struct fn_field *f, int j, + struct type* type, int offset)); extern value -value_virtual_fn_field PARAMS ((value arg1, struct fn_field *f, int j, - struct type *type)); +value_virtual_fn_field PARAMS ((value *arg1p, struct fn_field *f, int j, + struct type *type, int offset)); extern int binop_user_defined_p PARAMS ((enum exp_opcode op, value arg1, value arg2)); @@ -414,7 +424,7 @@ typecmp PARAMS ((int staticp, struct type *t1[], value t2[])); extern int destructor_name_p PARAMS ((const char *name, const struct type *type)); -#define value_free(val) free (val) +#define value_free(val) free ((PTR)val) extern void free_all_values PARAMS ((void)); diff --git a/gdb/values.c b/gdb/values.c index 8c299cc..aaff4126 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;