From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11723 invoked by alias); 9 Mar 2010 20:38:41 -0000 Received: (qmail 11699 invoked by uid 22791); 9 Mar 2010 20:38:38 -0000 X-SWARE-Spam-Status: No, hits=-7.0 required=5.0 tests=AWL,BAYES_00,HK_OBFDOM,KAM_STOCKGEN,RCVD_IN_DNSWL_HI,SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 09 Mar 2010 20:38:33 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o29KcVTL006775 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 9 Mar 2010 15:38:31 -0500 Received: from qcore.mollernet.net (vpn-234-186.phx2.redhat.com [10.3.234.186]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o29KcUbi009814 for ; Tue, 9 Mar 2010 15:38:30 -0500 Message-ID: <4B96B1C6.9050907@redhat.com> Date: Tue, 09 Mar 2010 20:38:00 -0000 From: Chris Moller User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b3pre) Gecko/20090513 Fedora/3.0-2.3.beta2.fc11 Thunderbird/3.0b2 MIME-Version: 1.0 To: gdb-patches@sourceware.org Subject: pr9065 patch Content-Type: multipart/mixed; boundary="------------080205030200060608070705" X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-03/txt/msg00369.txt.bz2 This is a multi-part message in MIME format. --------------080205030200060608070705 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1122 This is the typeid thing. This patch implements typeid in gdb, letting users do things like p typeid() p typeid().name() p typeid().__name p typeid().__is_pointer_() and the same thing for types (i.e., p typeid().name()) FWIW, you can even do stuff like set tp = typeid().name() (assuming there's a "char *tp;" in your source...) There are some differences, though, between the gdb typeid and the c++ typeid, the biggest is that the gdb version only partially implements the type_info class: it doesn't actually implement the methods, it just fakes them, and even though you can assign things like "set tp = typeid().name()" you can't assign "set ti = typeid()" where "type_info *ti;" Another difference is that the real typeid returns mangled names, leaving it to the user to demangle. This strikes me as a pain, so I just provide the demangled names. The attached patch works as advertised--see pr9065.exp for more details--but I haven't done a full regression yet. Feedback welcome, Chris --------------080205030200060608070705 Content-Type: text/x-patch; name="pr9065.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="pr9065.patch" Content-length: 17771 ? testsuite/gdb.cp/pr9065 Index: c-exp.y =================================================================== RCS file: /cvs/src/src/gdb/c-exp.y,v retrieving revision 1.70 diff -u -r1.70 c-exp.y --- c-exp.y 10 Feb 2010 18:57:21 -0000 1.70 +++ c-exp.y 9 Mar 2010 20:08:47 -0000 @@ -161,6 +161,7 @@ %} %type exp exp1 type_exp start variable qualified_name lcurly +%type opt_args %type rcurly %type type typebase qualified_type %type nonempty_typelist @@ -201,7 +202,7 @@ %token NAME_OR_INT %token OPERATOR -%token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON +%token STRUCT CLASS UNION ENUM SIZEOF UNSIGNED COLONCOLON TYPEID %token TEMPLATE %token ERROR %token NEW DELETE @@ -307,6 +308,41 @@ { write_exp_elt_opcode (UNOP_SIZEOF); } ; +exp : TYPEID exp %prec UNARY + { write_exp_elt_opcode (UNOP_TYPEID_VAR); } + ; + +exp : TYPEID '(' type ')' %prec UNARY + { write_exp_elt_opcode (OP_TYPE); + CHECK_TYPEDEF ($3); + write_exp_elt_type ($3); + write_exp_elt_opcode (OP_TYPE); + write_exp_elt_opcode (UNOP_TYPEID_TYPE); + write_exp_elt_longcst (0); + write_exp_elt_longcst ((LONGEST) 1); + write_exp_elt_opcode (UNOP_TYPEID_TYPE);} + ; + +exp : TYPEID '(' type ')' '.' name opt_args %prec UNARY + { write_exp_elt_opcode (OP_STRING); + write_exp_string ($6); + write_exp_elt_opcode (OP_STRING); + write_exp_elt_opcode (OP_TYPE); + CHECK_TYPEDEF ($3); + write_exp_elt_type ($3); + write_exp_elt_opcode (OP_TYPE); + write_exp_elt_opcode (UNOP_TYPEID_TYPE); + write_exp_elt_longcst ($7); + write_exp_elt_longcst ((LONGEST) 2); + write_exp_elt_opcode (UNOP_TYPEID_TYPE);} + ; + +opt_args : /* nothing */ + { $$ = 0; } + | '(' ')' + { $$ = 1; } + ; + exp : exp ARROW name { write_exp_elt_opcode (STRUCTOP_PTR); write_exp_string ($3); @@ -1897,6 +1933,7 @@ {"struct", STRUCT, OP_NULL, 0}, {"signed", SIGNED_KEYWORD, OP_NULL, 0}, {"sizeof", SIZEOF, OP_NULL, 0}, + {"typeid", TYPEID, OP_NULL, 0}, {"double", DOUBLE_KEYWORD, OP_NULL, 0}, {"false", FALSEKEYWORD, OP_NULL, 1}, {"class", CLASS, OP_NULL, 1}, Index: eval.c =================================================================== RCS file: /cvs/src/src/gdb/eval.c,v retrieving revision 1.127 diff -u -r1.127 eval.c --- eval.c 8 Feb 2010 20:55:42 -0000 1.127 +++ eval.c 9 Mar 2010 20:08:50 -0000 @@ -43,6 +43,7 @@ #include "gdb_obstack.h" #include "objfiles.h" #include "python/python.h" +#include "gdbcore.h" #include "gdb_assert.h" @@ -676,6 +677,314 @@ return type; } +static struct value * +create_type_info_class(char *type_name) +{ + int i, nfields; + int bitpos = -1; + struct type *typeid_type; + + typeid_type = lookup_struct ("std::type_info", NULL); + + for (i = 0; i < TYPE_NFIELDS (typeid_type); i++) + { + if (!strcmp ("__name", TYPE_FIELD_NAME (typeid_type, i))) + { + bitpos = TYPE_FIELD_BITPOS(typeid_type, i); + break; + } + } + if (bitpos != -1) + { + struct value *inferior_val; + CORE_ADDR inferior_addr; + struct value *rv; + struct value *val; + + val = allocate_value (typeid_type); + + inferior_val = value_allocate_space_in_inferior (1 + strlen (type_name)); + inferior_addr = value_as_address (inferior_val); + write_memory (inferior_addr, + type_name, strlen (type_name)); + + memcpy (value_contents_raw (val) + bitpos/8, + &inferior_addr, sizeof(inferior_addr)); + rv = value_coerce_to_target (val); + + return rv; + } + else error (_ ("Malformed type_info class")); +} + +static struct value * +fake_type_info_class(char *type_name, char *field_name, struct expression *exp, + int is_pointer, int is_function, int field_has_args) +{ + int i, nelms; + struct type *typeid_type; + + /* + We can't really evaluate typeid(). because it doesn't + really exist and creating it would be a pain. So we're just going + to assume the structure of class type_info is invariant and fake + the bits it that need faking. + */ + + typeid_type = lookup_struct ("std::type_info", NULL); + + nelms = TYPE_NFIELDS (typeid_type); + + for (i = 0; i < nelms; i++) + { + struct type *ft = TYPE_FIELD_TYPE(typeid_type, i); + int is_func = (TYPE_CODE (ft) == TYPE_CODE_METHOD + || TYPE_CODE (ft) == TYPE_CODE_FUNC); + if (!strcmp (field_name, TYPE_FIELD_NAME(typeid_type, i)) + && is_func == field_has_args) + { + typeid_type = language_string_char_type (exp->language_defn, + exp->gdbarch); + return value_cstring (type_name, 1+strlen (type_name), + typeid_type); + } + } + + nelms = TYPE_NFN_FIELDS_TOTAL (typeid_type); + + for (i = 0; i < nelms; i++) + { + struct fn_field *fn_fields; + struct type *ft; + int is_func; + + fn_fields = TYPE_FN_FIELDLIST1(typeid_type, i); + ft = TYPE_FN_FIELD_TYPE(fn_fields, 0); + is_func = (TYPE_CODE (ft) == TYPE_CODE_METHOD + || TYPE_CODE (ft) == TYPE_CODE_FUNC); + + if (!strcmp (field_name, TYPE_FN_FIELDLIST_NAME(typeid_type, i)) + && is_func == field_has_args) + { + /* + We're going to make the assumption that class typeinfo + isn't going to change. Given that, we need to handle: + + const char* name() + char *__name; + ==> return type string + + bool before(const type_info& __arg) + ==> warn not supported + + bool __is_pointer_p() + bool __is_function_p() + ==> return a bool + + The == and != operators won't appear here--maybe do + something about them somewhere else. + */ + + if (!strcmp (field_name, "name")) + { + typeid_type = language_string_char_type (exp->language_defn, + exp->gdbarch); + return value_cstring (type_name, 1+strlen (type_name), + typeid_type); + } + else if (!strcmp (field_name, "__is_pointer_p")) + { + return + value_from_longest (builtin_type (exp->gdbarch)->builtin_bool, + (LONGEST)is_pointer); + } + else if (!strcmp (field_name, "__is_function_p")) + { + return + value_from_longest (builtin_type (exp->gdbarch)->builtin_bool, + (LONGEST)is_function); + } + break; + } + } + error (_("%s is not a member of class type_info"), field_name); +} + +static struct value * +evaluate_subexp_for_typeid_type (struct expression *exp, int *pos) + __attribute__ ((noinline)); + +static struct value * +evaluate_subexp_for_typeid_type (struct expression *exp, int *pos) +{ + char *type_name; + struct type *type; + int pc; + int nargs; + struct type *typeid_type; + char *field_name; + int field_has_args; + int is_pointer = 0, is_function = 0; + + pc = (*pos); + (*pos) += 7; + + nargs = longest_to_int (exp->elts[pc + 1].longconst); + field_has_args = longest_to_int (exp->elts[pc].longconst); + + if (nargs == 1) + { + type = exp->elts[pc + 4].type; + field_name = NULL; + } + else + { + int tpos = pc + 3; + type = exp->elts[pc + 9].type; + exp->elts[tpos].opcode = exp->elts[tpos+7].opcode = STRUCTOP_STRUCT; + field_name = extract_field_op (exp, &tpos); + } + + if (TYPE_NAME (type)) + type_name = TYPE_NAME (type); + else if (TYPE_TAG_NAME (type)) + type_name = TYPE_TAG_NAME (type); + else + type_name = ""; + + if (nargs == 1) + return create_type_info_class(type_name); + else + return fake_type_info_class(type_name, field_name, exp, + is_pointer, is_function, field_has_args); +} + +static struct value * +evaluate_subexp_for_typeid_var (struct expression *exp, int *pos) +{ + enum exp_opcode op; + char *type_name = NULL; + struct type *typeid_type; + struct type *type = NULL; + struct value *val; + int show_deref = 0; + int is_pointer = 0; + int is_function = 0; + char *field_name = NULL; + struct type *symbol_type = NULL; + int has_args = 0; + + if (exp->elts[*pos].opcode == OP_FUNCALL) + { + + gdb_assert (longest_to_int (exp->elts[*pos + 1].longconst == 0)); + *pos += 3; /* Skip past the OP_FUNCALL. */ + + gdb_assert (exp->elts[*pos].opcode == STRUCTOP_STRUCT); + + field_name = extract_field_op (exp, pos); + has_args = 1; + } + else if (exp->elts[*pos].opcode == STRUCTOP_STRUCT) + field_name = extract_field_op (exp, pos); + + if (exp->elts[*pos].opcode == OP_VAR_VALUE) + { + struct symbol * sym = exp->elts[*pos + 2].symbol; + symbol_type = SYMBOL_TYPE (sym); + } + + if (exp->elts[*pos].opcode == OP_TYPE) + { + type = exp->elts[*pos + 1].type; + *pos += 3; + } + else + { + val = evaluate_subexp (NULL_TYPE, exp, pos, + EVAL_AVOID_SIDE_EFFECTS); + + type = check_typedef (value_type (val)); + } + + if (TYPE_CODE_REF == TYPE_CODE (type) + || TYPE_CODE_PTR == TYPE_CODE (type) + || TYPE_CODE_ARRAY == TYPE_CODE (type)) + { + struct type *target_type = TYPE_TARGET_TYPE(type); + type_name = TYPE_NAME (target_type); + is_pointer = 1; + show_deref = 1; + } + else if (TYPE_CODE_FUNC == TYPE_CODE (type)) + { + struct type *target_type = TYPE_TARGET_TYPE(type); + + if (TYPE_NAME (target_type)) + type_name = TYPE_NAME (target_type); + else if (TYPE_TAG_NAME (target_type)) + type_name = TYPE_TAG_NAME (target_type); + else + { + if (symbol_type) + { + target_type = TYPE_TARGET_TYPE(symbol_type); + if (target_type && TYPE_CODE_PTR == TYPE_CODE (target_type)) + { + target_type = TYPE_TARGET_TYPE(target_type); + if (TYPE_NAME (target_type)) + type_name = TYPE_NAME (target_type); + else if (TYPE_TAG_NAME (target_type)) + type_name = TYPE_TAG_NAME (target_type); + is_pointer = 1; + show_deref = 1; + } + else + { + if (TYPE_NAME (target_type)) + type_name = TYPE_NAME (target_type); + else if (TYPE_TAG_NAME (target_type)) + type_name = TYPE_TAG_NAME (target_type); + } + } + } + if (!type_name) type_name = ""; + is_function = 1; + } + else + { + if (TYPE_NAME (type)) + type_name = TYPE_NAME (type); + else if (TYPE_TAG_NAME (type)) + type_name = TYPE_TAG_NAME (type); + else + type_name = ""; + } + + if (TYPE_CODE_STRUCT == TYPE_CODE (type)) + { +#define STRUCT_LBL "struct " + char * tmp = alloca (1 + strlen (STRUCT_LBL) + strlen (type_name)); + strcpy (tmp, STRUCT_LBL); + strcat (tmp, type_name); + type_name = tmp; + } + + if (show_deref) { +#define DEREF_STAR " *" + char * tmp = alloca (1 + strlen (DEREF_STAR) + strlen (type_name)); + strcpy (tmp, type_name); + strcat (tmp, DEREF_STAR); + type_name = tmp; + } + + if (field_name == NULL) + return create_type_info_class(type_name); + else + return fake_type_info_class(type_name, field_name, exp, + is_pointer, is_function, has_args); +} + struct value * evaluate_subexp_standard (struct type *expect_type, struct expression *exp, int *pos, @@ -2468,6 +2777,23 @@ } return evaluate_subexp_for_sizeof (exp, pos); + case UNOP_TYPEID_TYPE: + if (noside == EVAL_SKIP) + { + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + goto nosideret; + } + return evaluate_subexp_for_typeid_type (exp, pos); + + case UNOP_TYPEID_VAR: + if (noside == EVAL_SKIP) + { + evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP); + goto nosideret; + } + return evaluate_subexp_for_typeid_var (exp, pos); + break; + case UNOP_CAST: (*pos) += 2; type = exp->elts[pc + 1].type; Index: expression.h =================================================================== RCS file: /cvs/src/src/gdb/expression.h,v retrieving revision 1.34 diff -u -r1.34 expression.h --- expression.h 18 Jan 2010 20:54:33 -0000 1.34 +++ expression.h 9 Mar 2010 20:08:50 -0000 @@ -265,6 +265,8 @@ UNOP_PREDECREMENT, /* -- before an expression */ UNOP_POSTDECREMENT, /* -- after an expression */ UNOP_SIZEOF, /* Unary sizeof (followed by expression) */ + UNOP_TYPEID_TYPE, /* Unary typeid (followed by expression) */ + UNOP_TYPEID_VAR, /* Unary typeid (followed by expression) */ UNOP_PLUS, /* Unary plus */ Index: parse.c =================================================================== RCS file: /cvs/src/src/gdb/parse.c,v retrieving revision 1.95 diff -u -r1.95 parse.c --- parse.c 10 Feb 2010 18:57:21 -0000 1.95 +++ parse.c 9 Mar 2010 20:08:51 -0000 @@ -863,6 +863,16 @@ oplen = 3; break; + case UNOP_TYPEID_TYPE: + oplen = 4; + args = longest_to_int (expr->elts[endpos - 2].longconst); + break; + + case UNOP_TYPEID_VAR: + oplen = 1; + args = 1; + break; + case BINOP_VAL: case UNOP_CAST: case UNOP_DYNAMIC_CAST: Index: testsuite/gdb.cp/Makefile.in =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/Makefile.in,v retrieving revision 1.9 diff -u -r1.9 Makefile.in --- testsuite/gdb.cp/Makefile.in 8 Feb 2010 18:27:53 -0000 1.9 +++ testsuite/gdb.cp/Makefile.in 9 Mar 2010 20:08:53 -0000 @@ -5,7 +5,7 @@ derivation inherit local member-ptr method misc \ overload ovldbreak ref-typ ref-typ2 templates userdef virtfunc namespace \ ref-types ref-params method2 pr9594 gdb2495 virtfunc2 pr9067 \ - pr1072 + pr1072 pr9065 all info install-info dvi install uninstall installcheck check: @echo "Nothing to be done for $@..." Index: testsuite/gdb.cp/pr9065.cc =================================================================== RCS file: testsuite/gdb.cp/pr9065.cc diff -N testsuite/gdb.cp/pr9065.cc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ testsuite/gdb.cp/pr9065.cc 9 Mar 2010 20:08:54 -0000 @@ -0,0 +1,55 @@ +using namespace std; +#include +#include +#include + +struct vs { + int i; + const char * c; +}; + +class cs { +private: + double ff; +public: + double getval() { return ff; } +}; + +typedef int * iptr; +typedef double dbl; +typedef struct vs vvs; + +char * +dummy_fcn() +{ + return NULL; +} + +double +dummy_dbl() +{ + return 8.5; +} + +int +main() +{ + char tpp[] = { "hi there" }; + const char * tp; + int gh; + int myArray[10]; + struct vs vsi; + + iptr iptri = NULL; + dbl dbli; + vvs vvsi; + + cs csi; + + tp = "bye bye"; + + vsi.i = 8888; + vsi.c = "garbage"; + + return 0; // bp marker +} Index: testsuite/gdb.cp/pr9065.exp =================================================================== RCS file: testsuite/gdb.cp/pr9065.exp diff -N testsuite/gdb.cp/pr9065.exp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ testsuite/gdb.cp/pr9065.exp 9 Mar 2010 20:08:54 -0000 @@ -0,0 +1,73 @@ +# Copyright 2010 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 . + +set testfile pr9065 +set srcfile ${testfile}.cc +if [prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}] { + return -1 +} + +if ![runto_main] { + untested pr9065 + return -1 +} + +gdb_breakpoint [gdb_get_line_number "bp marker"] +gdb_continue_to_breakpoint "bp marker" + +gdb_test "p typeid(tp).name()" "char \\*.*" +gdb_test "p typeid(*tp).name()" "char.*" +gdb_test "p typeid(tp\[0\]).name()" "char.*" +gdb_test "p typeid(tp\[0\]).__is_pointer_p()" "false.*" +gdb_test "p typeid(tp).__is_pointer_p()" "true.*" +gdb_test "p typeid(tp).__is_function_p()" "false.*" + +gdb_test "p typeid(tpp).name()" "char \\*.*" +gdb_test "p typeid(*tpp).name()" "char.*" +gdb_test "p typeid(tpp\[0\]).__name" "char.*" + +gdb_test "p typeid(gh).name()" "int.*" + +gdb_test "p typeid(myArray).name()" "int \\*.*" +gdb_test "p typeid(*myArray).name()" "int.*" +gdb_test "p typeid(myArray\[0\]).name()" "int.*" + +gdb_test "p typeid(vsi).name()" "struct vs.*" +gdb_test "p typeid(vsi.i).__name" "int.*" +gdb_test "p typeid(vsi.c).name()" "char \\*.*" + +gdb_test "p typeid(main).name()" "int.*" +gdb_test "p typeid(main).__is_pointer_p()" "false.*" +gdb_test "p typeid(main).__is_function_p()" "true.*" + +gdb_test "p typeid(vvsi).name()" "struct vs.*" + +gdb_test "p typeid(dbli).name()" "double.*" +gdb_test "p typeid(dbli).__is_pointer_p()" "false.*" +gdb_test "p typeid(dbli).__is_function_p()" "false.*" + +gdb_test "p typeid(iptri).__name" "int \\*.*" +gdb_test "p typeid(iptri).__is_pointer_p()" "true.*" +gdb_test "p typeid(iptri).__is_function_p()" "false.*" +gdb_test "p typeid(iptri)" "_vptr.type_info = 0x0, __name.*int \\*.*" + +gdb_test "p typeid(dummy_fcn).__name" "char \\*.*" +gdb_test "p typeid(dummy_fcn).__is_function_p()" "true.*" +gdb_test "p typeid(dummy_fcn).__is_pointer_p()" "true.*" + +gdb_test "p typeid(dummy_dbl).__name" "double.*" +gdb_test "p typeid(dummy_dbl).__is_function_p()" "true.*" +gdb_test "p typeid(dummy_dbl).__is_pointer_p()" "false.*" + --------------080205030200060608070705--