This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC]: java inferior function call support


The following patch adds initial support for simple java inferior calls. Standard calls are either calling a member function of a variable which is a class or a static member function of a class by name. There are a number of complex scenarios that do not work, but this patch lays the groundwork for supporting them in the future.

There a few differences between Java and C++ that require handling. First of all, the Java debug info for a member has a fully qualified name including prototype. There is an open bugzilla bug against gcj for this, however, I think some rethinking may be required. In a recent C++ bug, I have found that C++ does not correctly list or properly allow selection of multiple constructors with varying prototypes. It gets the line numbers and prototypes all wrong. Java, surprisingly, does the right thing. It lists the correct line numbers and prototypes, and selection works properly. The fully qualified member name does interfere with tab completion so there is work required. I have dealt with the gcj problem by parsing out the qualifiers and prototype for a Java member name.

Another key difference is how the vtable is structured. For Java, the vtable is an array of function pointers and is located by the first word of every class. It is much more complex for C++ so I have forked the logic that accesses the vtable in gnu-v3-abi.c.

Ok to commit or comments?

-- Jeff J.

2004-03-23 Jeff Johnston <jjohnstn@redhat.com>

        * dwarfread2.c (dwarf2_add_member_fn): Add support for Java's
        format for member name debug info.
        * gdbtypes.h (TYPE_JAVA_FN_FIELD_VOFFSET): New macro.
        * gnu-v3-abi.c (build_gdb_vtable_type): Adjust comment.
        (java_vtable_type_gdbarch_data): New static data.
        (build_gdb_java_vtable_type): New function.
        (gnuv3_virtual_fn_field): Add support for Java vtable.
        (init_gnuv3_ops): Add building the Java vtable type.
        * valarith.c (value_subscript_1): New function that takes
        c_style as argument.
        (value_subscript): Change to call value_subscript_1.
        * value.h (value_subscript_1): New prototype.
        * symtab.c (lookup_symbol): Support Java demangling.
        * jv-exp.y (FuncStart): New semantic for a function call.
        (MethodInvocation): Support standard function calls.  Change
        the error message for forms of function calls not yet supported.



Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.141
diff -u -p -r1.141 dwarf2read.c
--- dwarf2read.c	16 Mar 2004 22:43:15 -0000	1.141
+++ dwarf2read.c	23 Mar 2004 18:31:07 -0000
@@ -2986,7 +2986,29 @@ dwarf2_add_member_fn (struct field_info 
   /* Get name of member function.  */
   attr = dwarf2_attr (die, DW_AT_name, cu);
   if (attr && DW_STRING (attr))
-    fieldname = DW_STRING (attr);
+    {
+      /* Note: C++ and Java currently differ in how the member function
+         name is stored in the debug info.  For Java, the member name is
+	 fully qualified with prototype while C++ just has the member
+	 name.  To get the Java member name, we strip off any dot qualifiers
+	 and remove the trailing prototype.  */
+      char *dot_index;
+      char *lparen;
+      fieldname = DW_STRING (attr);
+      if (cu->language == language_java)
+	{
+          dot_index = strchr (fieldname, '.');
+          while (dot_index)
+	    {
+	      fieldname = dot_index + 1;
+              dot_index = strchr (fieldname, '.');
+	    }
+          lparen = strchr (fieldname + 1, '(');
+          if (lparen)
+	    fieldname = obsavestring (fieldname, lparen - fieldname,
+		     	    	      &objfile->objfile_obstack);
+	}
+    }
   else
     return;
 
Index: gdbtypes.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbtypes.h,v
retrieving revision 1.52
diff -u -p -r1.52 gdbtypes.h
--- gdbtypes.h	7 Feb 2004 16:57:55 -0000	1.52
+++ gdbtypes.h	23 Mar 2004 18:31:07 -0000
@@ -905,6 +905,7 @@ extern void allocate_cplus_struct_type (
 #define TYPE_FN_FIELD_INLINED(thisfn, n) ((thisfn)[n].is_inlined)
 #define TYPE_FN_FIELD_FCONTEXT(thisfn, n) ((thisfn)[n].fcontext)
 #define TYPE_FN_FIELD_VOFFSET(thisfn, n) ((thisfn)[n].voffset-2)
+#define TYPE_JAVA_FN_FIELD_VOFFSET(thisfn, n) ((thisfn)[n].voffset)
 #define TYPE_FN_FIELD_VIRTUAL_P(thisfn, n) ((thisfn)[n].voffset > 1)
 #define TYPE_FN_FIELD_STATIC_P(thisfn, n) ((thisfn)[n].voffset == VOFFSET_STATIC)
 
Index: gnu-v3-abi.c
===================================================================
RCS file: /cvs/src/src/gdb/gnu-v3-abi.c,v
retrieving revision 1.21
diff -u -p -r1.21 gnu-v3-abi.c
--- gnu-v3-abi.c	15 Mar 2004 20:38:08 -0000	1.21
+++ gnu-v3-abi.c	23 Mar 2004 18:31:07 -0000
@@ -27,6 +27,7 @@
 #include "demangle.h"
 #include "gdb_assert.h"
 #include "gdb_string.h"
+#include "language.h"
 
 static struct cp_abi_ops gnu_v3_abi_ops;
 
@@ -95,7 +96,7 @@ enum {
 /* Return a GDB type representing `struct gdb_gnu_v3_abi_vtable',
    described above, laid out appropriately for ARCH.
 
-   We use this function as the gdbarch per-architecture data
+   We use this function as a gdbarch per-architecture data
    initialization function.  We assume that the gdbarch framework
    calls the per-architecture data initialization functions after it
    sets current_gdbarch to the new architecture.  */
@@ -170,6 +171,26 @@ build_gdb_vtable_type (struct gdbarch *a
   return t;
 }
 
+/* For Java, the vtable is different than C++.  It is simply an
+   array of function pointers.  */
+static struct gdbarch_data *java_vtable_type_gdbarch_data;
+
+/* Return a GDB type representing a Java vtable.
+   We use this function in the gdbarch per-architecture data
+   initialization function.  We assume that the gdbarch framework
+   calls the per-architecture data initialization functions after it
+   sets current_gdbarch to the new architecture.  */
+static void *
+build_gdb_java_vtable_type (struct gdbarch *arch)
+{
+  struct type *t;
+  struct type *ptr_to_void_fn_type
+    = lookup_pointer_type (lookup_function_type (builtin_type_void));
+  
+  t = create_array_type (0, ptr_to_void_fn_type,
+			 create_range_type (0, builtin_type_int, 0, -1));
+  return t;
+}
 
 /* Return the offset from the start of the imaginary `struct
    gdb_gnu_v3_abi_vtable' object to the vtable's "address point"
@@ -294,49 +315,81 @@ gnuv3_virtual_fn_field (struct value **v
   if (TYPE_CODE (value_type) != TYPE_CODE_CLASS)
     error ("Only classes can have virtual functions.");
 
-  /* Find the base class that defines this virtual function.  */
-  vfn_base = TYPE_FN_FIELD_FCONTEXT (f, j);
-  if (! vfn_base)
-    /* In programs compiled with G++ version 1, the debug info doesn't
-       say which base class defined the virtual function.  We'll guess
-       it's the same base class that has our vtable; this is wrong for
-       multiple inheritance, but it's better than nothing.  */
-    vfn_base = TYPE_VPTR_BASETYPE (type);
-
-  /* This type may have been defined before its virtual function table
-     was.  If so, fill in the virtual function table entry for the
-     type now.  */
-  if (TYPE_VPTR_FIELDNO (vfn_base) < 0)
-    fill_in_vptr_fieldno (vfn_base);
-  if (TYPE_VPTR_FIELDNO (vfn_base) < 0)
-    error ("Could not find virtual table pointer for class \"%s\".",
-	   TYPE_TAG_NAME (vfn_base) ? TYPE_TAG_NAME (vfn_base) : "<unknown>");
-
-  /* Now that we know which base class is defining our virtual
-     function, cast our value to that baseclass.  This takes care of
-     any necessary `this' adjustments.  */
-  if (vfn_base != value_type)
-    value = value_cast (vfn_base, value);
-
-  /* Now value is an object of the appropriate base type.  Fetch its
-     virtual table.  */
-  /* It might be possible to do this cast at the same time as the above.
-     Does multiple inheritance affect this?
-     Can this even trigger, or is TYPE_VPTR_BASETYPE idempotent?
-  */
-  if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base)
-    value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value);
-  vtable_address
-    = value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base)));
-
-  vtable = value_at_lazy (vtable_type,
-                          vtable_address - vtable_address_point_offset (),
-                          VALUE_BFD_SECTION (value));
-
-  /* Fetch the appropriate function pointer from the vtable.  */
-  vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions),
-                         value_from_longest (builtin_type_int,
-                                             TYPE_FN_FIELD_VOFFSET (f, j)));
+  /* C++ and java have different vtable mechanisms.  Check the language
+     first.  */
+  if (current_language->la_language == language_java)
+    {
+      /* For Java, the vtable address is the first word of the class object.
+	 It is simply an array of function pointers.  */
+      struct value *vtable_ptr;
+      struct type *ptr_to_void_fn_type
+	= lookup_pointer_type (lookup_function_type (builtin_type_void));
+      struct type *ptr_to_void_type
+	= lookup_pointer_type (builtin_type_void);
+      struct type *java_vtable_type 
+	= gdbarch_data (current_gdbarch, java_vtable_type_gdbarch_data);
+
+      vtable_ptr = value_at_lazy (ptr_to_void_type, VALUE_ADDRESS (value), 
+				  VALUE_BFD_SECTION (value));
+      vtable_address = value_as_address (vtable_ptr);
+      vtable = value_at_lazy (java_vtable_type,
+			      vtable_address,
+			      VALUE_BFD_SECTION (value));
+      /* Fetch the appropriate function pointer from the vtable.  
+         Note that the voffset should not be adjusted.  Thus, we cannot
+         use the TYPE_FN_FIELD_OFFSET macro.  */
+      vfn = value_subscript_1 (vtable,
+			       value_from_longest (builtin_type_int,
+						   TYPE_JAVA_FN_FIELD_VOFFSET (f, j)),
+			       1);
+    }
+  else /* C++ */
+    {
+      /* Find the base class that defines this virtual function.  */
+      vfn_base = TYPE_FN_FIELD_FCONTEXT (f, j);
+      if (! vfn_base)
+	/* In programs compiled with G++ version 1, the debug info doesn't
+	   say which base class defined the virtual function.  We'll guess
+	   it's the same base class that has our vtable; this is wrong for
+	   multiple inheritance, but it's better than nothing.  */
+	vfn_base = TYPE_VPTR_BASETYPE (type);
+      
+      /* This type may have been defined before its virtual function table
+	 was.  If so, fill in the virtual function table entry for the
+	 type now.  */
+      if (TYPE_VPTR_FIELDNO (vfn_base) < 0)
+	fill_in_vptr_fieldno (vfn_base);
+      if (TYPE_VPTR_FIELDNO (vfn_base) < 0)
+	error ("Could not find virtual table pointer for class \"%s\".",
+	       TYPE_TAG_NAME (vfn_base) ? TYPE_TAG_NAME (vfn_base) : "<unknown>");
+      
+      /* Now that we know which base class is defining our virtual
+	 function, cast our value to that baseclass.  This takes care of
+	 any necessary `this' adjustments.  */
+      if (vfn_base != value_type)
+	value = value_cast (vfn_base, value);
+      
+      /* Now value is an object of the appropriate base type.  Fetch its
+	 virtual table.  */
+      /* It might be possible to do this cast at the same time as the above.
+	 Does multiple inheritance affect this?
+	 Can this even trigger, or is TYPE_VPTR_BASETYPE idempotent?
+      */
+      if (TYPE_VPTR_BASETYPE (vfn_base) != vfn_base)
+	value = value_cast (TYPE_VPTR_BASETYPE (vfn_base), value);
+      vtable_address
+	= value_as_address (value_field (value, TYPE_VPTR_FIELDNO (vfn_base)));
+      
+      vtable = value_at_lazy (vtable_type,
+			      vtable_address - vtable_address_point_offset (),
+			      VALUE_BFD_SECTION (value));
+      
+      /* Fetch the appropriate function pointer from the vtable.  */
+      vfn = value_subscript (value_field (vtable, vtable_field_virtual_functions),
+			     value_from_longest (builtin_type_int,
+						 TYPE_FN_FIELD_VOFFSET (f, j)));
+      
+    }
 
   /* Cast the function pointer to the appropriate type.  */
   vfn = value_cast (lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j)),
@@ -423,6 +476,8 @@ static void
 init_gnuv3_ops (void)
 {
   vtable_type_gdbarch_data = gdbarch_data_register_post_init (build_gdb_vtable_type);
+
+  java_vtable_type_gdbarch_data = gdbarch_data_register_post_init (build_gdb_java_vtable_type);
 
   gnu_v3_abi_ops.shortname = "gnu-v3";
   gnu_v3_abi_ops.longname = "GNU G++ Version 3 ABI";
Index: jv-exp.y
===================================================================
RCS file: /cvs/src/src/gdb/jv-exp.y,v
retrieving revision 1.18
diff -u -p -r1.18 jv-exp.y
--- jv-exp.y	23 Nov 2003 20:41:17 -0000	1.18
+++ jv-exp.y	23 Mar 2004 18:31:07 -0000
@@ -446,13 +446,22 @@ FieldAccess:
 /*|	SUPER '.' SimpleName { FIXME } */
 ;
 
+FuncStart:
+	Name '('
+                { push_expression_name ($1); }
+;
+
 MethodInvocation:
-	Name '(' ArgumentList_opt ')'
-		{ error (_("Method invocation not implemented")); }
+	FuncStart
+                { start_arglist(); }
+	ArgumentList_opt ')'
+                { write_exp_elt_opcode (OP_FUNCALL);
+		  write_exp_elt_longcst ((LONGEST) end_arglist ());
+		  write_exp_elt_opcode (OP_FUNCALL); }
 |	Primary '.' SimpleName '(' ArgumentList_opt ')'
-		{ error (_("Method invocation not implemented")); }
+		{ error (_("Form of method invocation not implemented")); }
 |	SUPER '.' SimpleName '(' ArgumentList_opt ')'
-		{ error (_("Method invocation not implemented")); }
+		{ error (_("Form of method invocation not implemented")); }
 ;
 
 ArrayAccess:
Index: symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.128
diff -u -p -r1.128 symtab.c
--- symtab.c	19 Feb 2004 19:01:26 -0000	1.128
+++ symtab.c	23 Mar 2004 18:31:08 -0000
@@ -41,6 +41,7 @@
 #include "source.h"
 #include "filenames.h"		/* for FILENAME_CMP */
 #include "objc-lang.h"
+#include "jv-lang.h"
 
 #include "hashtab.h"
 
@@ -932,11 +933,13 @@ lookup_symbol (const char *name, const s
 
   modified_name = name;
 
-  /* If we are using C++ language, demangle the name before doing a lookup, so
+  /* If we are using C++ or Java, demangle the name before doing a lookup, so
      we can always binary search. */
-  if (current_language->la_language == language_cplus)
+  if (current_language->la_language == language_cplus ||
+      current_language->la_language == language_java)
     {
-      demangled_name = cplus_demangle (name, DMGL_ANSI | DMGL_PARAMS);
+      demangled_name = language_demangle (current_language, name,
+		      			  DMGL_ANSI | DMGL_PARAMS);
       if (demangled_name)
 	{
 	  mangled_name = name;
Index: valarith.c
===================================================================
RCS file: /cvs/src/src/gdb/valarith.c,v
retrieving revision 1.21
diff -u -p -r1.21 valarith.c
--- valarith.c	14 Sep 2003 16:32:14 -0000	1.21
+++ valarith.c	23 Mar 2004 18:31:08 -0000
@@ -171,17 +171,24 @@ an integer nor a pointer of the same typ
   return value_binop (arg1, arg2, BINOP_SUB);
 }
 
+/* Return the value of ARRAY[IDX].  */
+
+struct value *
+value_subscript (struct value *array, struct value *idx)
+{
+  return value_subscript_1 (array, idx, current_language->c_style_arrays);
+}
+
 /* Return the value of ARRAY[IDX].
+   If C_STYLE is true, do not perform range checking. 
    See comments in value_coerce_array() for rationale for reason for
    doing lower bounds adjustment here rather than there.
    FIXME:  Perhaps we should validate that the index is valid and if
-   verbosity is set, warn about invalid indices (but still use them). */
-
+   verbosity is set, warn about invalid indices (but still use them).  */
 struct value *
-value_subscript (struct value *array, struct value *idx)
+value_subscript_1 (struct value *array, struct value *idx, int c_style)
 {
   struct value *bound;
-  int c_style = current_language->c_style_arrays;
   struct type *tarray;
 
   COERCE_REF (array);
Index: value.h
===================================================================
RCS file: /cvs/src/src/gdb/value.h,v
retrieving revision 1.54
diff -u -p -r1.54 value.h
--- value.h	23 Oct 2003 22:36:14 -0000	1.54
+++ value.h	23 Mar 2004 18:31:08 -0000
@@ -416,6 +416,9 @@ extern struct value *value_repeat (struc
 
 extern struct value *value_subscript (struct value *array, struct value *idx);
 
+extern struct value *value_subscript_1 (struct value *array, 
+		                        struct value *idx, int c_style);
+
 extern struct value *register_value_being_returned (struct type *valtype,
 						    struct regcache *retbuf);
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]