Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* pr9065 patch
@ 2010-03-09 20:38 Chris Moller
  2010-03-10  4:11 ` Eli Zaretskii
  2010-03-11 21:32 ` Tom Tromey
  0 siblings, 2 replies; 6+ messages in thread
From: Chris Moller @ 2010-03-09 20:38 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1122 bytes --]

This is the typeid thing.

This patch implements typeid in gdb, letting users do things like

    p typeid(<expression>)
    p typeid(<expression>).name()
    p typeid(<expression>).__name
    p typeid(<expression>).__is_pointer_()

and the same thing for types (i.e., p typeid(<type>).name())

FWIW, you can even do stuff like

    set tp = typeid(<expression>).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(<expression>).name()" you can't assign "set ti = 
typeid(<expression>)" 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


[-- Attachment #2: pr9065.patch --]
[-- Type: text/x-patch, Size: 17771 bytes --]

? 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 <voidval> exp exp1 type_exp start variable qualified_name lcurly
+%type <lval> opt_args
 %type <lval> rcurly
 %type <tval> type typebase qualified_type
 %type <tvec> nonempty_typelist
@@ -201,7 +202,7 @@
 %token <ssym> 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(<var>).<member> 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 = "<anonymous>";
+  
+  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 = "<anonymous>";
+      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 = "<anonymous>";
+    }
+  
+  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 <stdio.h>
+#include <iostream>
+#include <typeinfo>
+
+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 <http://www.gnu.org/licenses/>.
+
+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.*"
+

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: pr9065 patch
  2010-03-09 20:38 pr9065 patch Chris Moller
@ 2010-03-10  4:11 ` Eli Zaretskii
  2010-03-10 12:34   ` Chris Moller
  2010-03-11 21:32 ` Tom Tromey
  1 sibling, 1 reply; 6+ messages in thread
From: Eli Zaretskii @ 2010-03-10  4:11 UTC (permalink / raw)
  To: Chris Moller; +Cc: gdb-patches

> Date: Tue, 09 Mar 2010 15:38:30 -0500
> From: Chris Moller <cmoller@redhat.com>
> 
> This is the typeid thing.
> 
> This patch implements typeid in gdb, letting users do things like
> 
>     p typeid(<expression>)
>     p typeid(<expression>).name()
>     p typeid(<expression>).__name
>     p typeid(<expression>).__is_pointer_()
> 
> and the same thing for types (i.e., p typeid(<type>).name())

Thanks.  I think this needs a suitable patch to the manual as well.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: pr9065 patch
  2010-03-10  4:11 ` Eli Zaretskii
@ 2010-03-10 12:34   ` Chris Moller
  0 siblings, 0 replies; 6+ messages in thread
From: Chris Moller @ 2010-03-10 12:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On 03/09/10 23:11, Eli Zaretskii wrote:
>> Date: Tue, 09 Mar 2010 15:38:30 -0500
>> From: Chris Moller<cmoller@redhat.com>
>>
>> This is the typeid thing.
>>
>> This patch implements typeid in gdb, letting users do things like
>>
>>      p typeid(<expression>)
>>      p typeid(<expression>).name()
>>      p typeid(<expression>).__name
>>      p typeid(<expression>).__is_pointer_()
>>
>> and the same thing for types (i.e., p typeid(<type>).name())
>>      
>
> Thanks.  I think this needs a suitable patch to the manual as well.
>    

Okay, I'll add that for the final version.  (There ar a couple of other 
minor things I remembered after I sent the patch out yesterday, like 
patching expprint.c to include the new opcode enums.)


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: pr9065 patch
  2010-03-09 20:38 pr9065 patch Chris Moller
  2010-03-10  4:11 ` Eli Zaretskii
@ 2010-03-11 21:32 ` Tom Tromey
  2010-03-12 14:22   ` Chris Moller
  2010-03-22 12:19   ` pr9065 patch (the typeid thing) Chris Moller
  1 sibling, 2 replies; 6+ messages in thread
From: Tom Tromey @ 2010-03-11 21:32 UTC (permalink / raw)
  To: Chris Moller; +Cc: gdb-patches

>>>>> "Chris" == Chris Moller <cmoller@redhat.com> writes:

Chris> This is the typeid thing.
Chris> This patch implements typeid in gdb, letting users do things like

Chris> There are some differences, though, between the gdb typeid and the c++
Chris> typeid, the biggest is that the gdb version only partially implements
Chris> the type_info class: it doesn't actually implement the methods, it
Chris> just fakes them, and even though you can assign things like "set tp =
Chris> typeid(<expression>).name()" you can't assign "set ti =
Chris> typeid(<expression>)" where "type_info *ti;"

I think our goal ought to be no differences from the C++ compiler.

It isn't actually that useful, I think, to just print a typeid in gdb.
We have other, better, mechanisms for inspecting types.  Instead, the
reason to implement typeid in the first place is to preserve the "cut
and paste" property: if the user cuts an expression from their source
and pastes it into gdb, it should yield the same answer as their
compiled code would.

Deviations from this principle are confusing to users.

Chris> Another difference is that the real typeid returns mangled names,
Chris> leaving it to the user to demangle.  This strikes me as a pain, so I
Chris> just provide the demangled names.

It should be compatible.  GDB has a demangle command for this purpose.

Chris> +exp	:       TYPEID '(' type ')' '.' name opt_args	%prec UNARY
Chris> +                        { write_exp_elt_opcode (OP_STRING);
Chris> +			  write_exp_string ($6);
Chris> +			  write_exp_elt_opcode (OP_STRING);

I guess the problem is that type_id::name is an inlined function with no
out-of-line instance in libstdc++.  So, there is no way to call it.

I think we should have a way to make a fake method, but I don't think it
should be implemented in an ad hoc way.  Instead it should be a general
facility.  That should be a separate patch.  For the plain "introduce
typeid" patch, I think it is fine if it just barfs for anything not
provided by libstc++.

This is what Daniel was referring to when he mentioned writing
"not-outlined" methods in Python.  And, I agree that this would be the
way to go; for one thing it would let library implementers provide the
implementations, alongside their pretty-printers and whatnot.

Chris> +static struct value *
Chris> +create_type_info_class(char *type_name)

New functions need an introductory comment.

There is a missing space before the "("; this occurs in many places
in the patch.

It is best to be const-correct.  I assume the argument can be a
const char *.

Chris> +      val = allocate_value (typeid_type);
Chris> +      
Chris> +      inferior_val = value_allocate_space_in_inferior (1 + strlen (type_name));
Chris> +      inferior_addr = value_as_address (inferior_val);
Chris> +      write_memory (inferior_addr,
Chris> +		    type_name, strlen (type_name));
Chris> +      
Chris> +      memcpy (value_contents_raw (val) + bitpos/8,
Chris> +	      &inferior_addr, sizeof(inferior_addr));
Chris> +      rv = value_coerce_to_target (val);

The call to write_memory is not copying the trailing \0.

This code seems odd to me.  IIUC, the type_info for a type is stored as
a global symbol.  This way, typeid always returns the same object for a
given type, and thus the result can be compared with ==.  (This is true
on some platforms anyhow, there are tweaks for other cases, see
libsupc++.)  Making our own type_info is going to yield incorrect
results where there is a single type_info object per type.

Chris> +static struct value *
Chris> +fake_type_info_class(char *type_name, char *field_name, struct expression *exp,
Chris> +		     int is_pointer, int is_function, int field_has_args)

This should probably just go away.  As above, I don't think this is the
way we want to handle the missing methods.

Chris> +	    We're going to make the assumption that class typeinfo
Chris> +	    isn't going to change.  Given that, we need to handle:

This is a reasonable assumption for the current ABI, but it is not
reasonable to assume it universally.  If this sort of thing is still
needed, you have to hide it behind the appropriate API, see cp-abi.h.

Chris> +static struct value *
Chris> +evaluate_subexp_for_typeid_type (struct expression *exp, int *pos)
Chris> +     __attribute__ ((noinline));

Just remove this.  For future reference, you can't use __attribute__
unconditionally in (most of) gdb, you have to hide it behind a define.
See defs.h.

Chris> +  if (TYPE_CODE_STRUCT ==  TYPE_CODE (type))
Chris> +    {
Chris> +#define STRUCT_LBL "struct "
Chris> +      char * tmp = alloca (1 + strlen (STRUCT_LBL) + strlen (type_name));
Chris> +      strcpy (tmp, STRUCT_LBL);

I think it is nice to #undef such local defines after their use.
That way, it is almost like they have proper scoping.

Tom


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: pr9065 patch
  2010-03-11 21:32 ` Tom Tromey
@ 2010-03-12 14:22   ` Chris Moller
  2010-03-22 12:19   ` pr9065 patch (the typeid thing) Chris Moller
  1 sibling, 0 replies; 6+ messages in thread
From: Chris Moller @ 2010-03-12 14:22 UTC (permalink / raw)
  To: tromey; +Cc: gdb-patches

On 03/11/10 16:32, Tom Tromey wrote:
>
> I guess the problem is that type_id::name is an inlined function with no
> out-of-line instance in libstdc++.  So, there is no way to call it.
>    

Yeah, I tried it anyway with a few variation of 
find_function_in_inferior ("std::type_info.name",...).  Didn't work, 
which is why I was using a fake-out approach.

>
> Chris>  +static struct value *
> Chris>  +evaluate_subexp_for_typeid_type (struct expression *exp, int *pos)
> Chris>  +     __attribute__ ((noinline));
>
> Just remove this.  For future reference, you can't use __attribute__
> unconditionally in (most of) gdb, you have to hide it behind a define.
> See defs.h.
>    

Yeah, that was just there for debugging to keep the fcn from being 
inlined--I meant to take it out before making the patch.

I'm incorporating what I can of the rest of your comments, and trying to 
figure out how to do a "not-outlined method."


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: pr9065 patch (the typeid thing)
  2010-03-11 21:32 ` Tom Tromey
  2010-03-12 14:22   ` Chris Moller
@ 2010-03-22 12:19   ` Chris Moller
  1 sibling, 0 replies; 6+ messages in thread
From: Chris Moller @ 2010-03-22 12:19 UTC (permalink / raw)
  To: tromey; +Cc: gdb-patches

On 03/11/10 16:32, Tom Tromey wrote:
>
> Chris>  Another difference is that the real typeid returns mangled names,
> Chris>  leaving it to the user to demangle.  This strikes me as a pain, so I
> Chris>  just provide the demangled names.
>
> It should be compatible.  GDB has a demangle command for this purpose.
>
>    

I've done a lot of re-write on this patch over the last week or so, but 
the requirement for returning mangled names turns out to be a bit of a 
stopper:  mangled names for built-in types don't exist at all in gdb, 
and mangled names for symbols are only occasionally available.

My first thought was to clone the gcc mangler; my second thought was 
that's not really the best solution.  I don't know if it's intended for 
gdb to be able to debug stuff compiled by anything other than gcc, but 
since every compiler uses its own mangling algo, forcing the use of the 
gcc mangling algo certainly wouldn't be compatible with that.  Also, 
though I don't know how likely it is, it's not impossible that the gcc 
algo could change.

At least one of the probable reasons mangled symbol names aren't 
available seems to be that they're not emitted in the DWARF.  In my 
testcase, of the dozen or so vars and fcns I use, the mangled name of 
only one of them appears in the DWARF (tagged with 
DW_AT_MIPS_linkage_name--why just that one symbol and nothing else, I 
haven't a clue), so my guess is that if gcc could somehow be convinced 
to emit the mangled names of all symbols and primitive types, things 
would be cool, but I don't know how hard it would be to get gcc (i.e., 
its maintainers) to do that..  (I couldn't find a gcc option that made 
that happen...)

Chris


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-03-22 12:19 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-09 20:38 pr9065 patch Chris Moller
2010-03-10  4:11 ` Eli Zaretskii
2010-03-10 12:34   ` Chris Moller
2010-03-11 21:32 ` Tom Tromey
2010-03-12 14:22   ` Chris Moller
2010-03-22 12:19   ` pr9065 patch (the typeid thing) Chris Moller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox