This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java 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]

_Jv_Debug


Those of you who work on gcc will know about the functions debug_rtx()
and debug_tree().  These present a somewhat readble debug version of
the gcj internal objects.

With this in mind, I have created _Jv_Debug, which does something
similar.  In gdb you can do this:

(gdb) p _Jv_Debug(0x80a9890)
gnu.gcj.convert.Output_8859_1@80a9890
{
  static boolean iconv_byte_swap = false,
  static int CACHE_SIZE = 4,
  static int currCachePos = 0,
  int count = 0,
  static java.util.Hashtable hash = java.util.Hashtable@8096f50
    {
      static int VALUES = 1,
      java.util.Set entries = null,
      float loadFactor = 0.75,
      static float DEFAULT_LOAD_FACTOR = 0.75,
      int modCount = 31,
      static int ENTRIES = 2,
      static int DEFAULT_CAPACITY = 11,
      static long serialVersionUID = 1421746759512286392,
      int size = 31,
      static int KEYS = 0,
      java.util.Collection values = null,
      int threshold = 35,
      java.util.Set keys = null,
      static long serialVersionUID = 1196656838076753133,
      [Ljava.util.Hashtable$HashEntry; buckets = 0x8091d00,
    },
  static java.lang.String defaultEncoding = "8859_1",
  static [Lgnu.gcj.convert.UnicodeToBytes; encoderCache = [Lgnu.gcj.convert.UnicodeToBytes;@80791c8
    {
      null, null, null, null, 
    },
  [B buf = [B@809cee0
    {
      72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, ...
    },
}

or this:

p _Jv_DeepDebug(0x80a9890,0)
gnu.gcj.convert.Output_8859_1@80a9890
{
  static boolean iconv_byte_swap = false,
  static int CACHE_SIZE = 4,
  static int currCachePos = 0,
  int count = 0,
  static java.util.Hashtable hash = 0x8096f50,
  static java.lang.String defaultEncoding = "8859_1",
  static [Lgnu.gcj.convert.UnicodeToBytes; encoderCache = 0x80791c8,
  [B buf = 0x809cee0,
}

which is rather nice, I think.  [There is a small problem -- gdb won't
let you call a function in the inferior when you're in "java mode".
You have to do "set lang c++".  We should easily be able to fix this
in gdb.]

The new ABI has dynamic object structures, and so it will be hard for
gdb to print their contents: the static debugging data will be
useless.  This method is a way to solve that problem.

One problem with this approach (as opposed to gdb doing the work) is
that it can trigger gc, finalizers, memory allocation, and so on, so
it's not a perfect solution.

Andrew.


2004-03-01  Andrew Haley  <aph@redhat.com>

	* gnu/gcj/util/Debug.java: New file.
	* gnu/gcj/util/natDebug.cc: New file.
	* Makefile.am: Add Debug.java, natDebug.cc.
	* Makefile.in: Regenerated

Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.362
diff -p -2 -c -r1.362 Makefile.am
*** Makefile.am	26 Feb 2004 10:04:38 -0000	1.362
--- Makefile.am	1 Mar 2004 20:58:43 -0000
*************** gnu/gcj/runtime/StackTrace.java \
*** 2176,2179 ****
--- 2176,2180 ----
  gnu/gcj/runtime/StringBuffer.java \
  gnu/gcj/runtime/VMClassLoader.java \
+ gnu/gcj/util/Debug.java \
  gnu/java/io/ASN1ParsingException.java \
  gnu/java/io/Base64InputStream.java \
*************** gnu/gcj/runtime/natStackTrace.cc \
*** 2819,2822 ****
--- 2820,2824 ----
  gnu/gcj/runtime/natStringBuffer.cc \
  gnu/gcj/runtime/natVMClassLoader.cc \
+ gnu/gcj/util/natDebug.cc \
  gnu/java/awt/natEmbeddedWindow.cc \
  gnu/java/net/natPlainDatagramSocketImpl.cc \
Index: gnu/gcj/util/Debug.java
===================================================================
RCS file: gnu/gcj/util/Debug.java
diff -N gnu/gcj/util/Debug.java
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gnu/gcj/util/Debug.java	1 Mar 2004 20:58:43 -0000
***************
*** 0 ****
--- 1,192 ----
+ /*  Copyright (C) 2004  Free Software Foundation
+ 
+ This file is part of libgcj.
+ 
+ This software is copyrighted work licensed under the terms of the
+ Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+ details.  */
+ 
+ /* Utility methods that allow an object to be converted to a textual
+    representation on an OutputStream.  The intention here is that this
+    class be used for debugging, so we provide information about all
+    fields, public or otherwise. */
+ 
+ package gnu.gcj.util;
+ 
+ import java.lang.reflect.*;
+ import java.io.*;
+ import java.util.*;
+ 
+ class Debug 
+ {
+   private final PrintStream p;
+   private final int maxdepth;
+   private final int maxArrayLength;
+   private int depth; 
+ 
+   Debug(PrintStream writer, int maxdepth, int maxArrayLength)
+   {
+     p = writer;
+     this.maxdepth = maxdepth;
+     this.maxArrayLength = maxArrayLength;
+   }
+ 
+   Debug(PrintStream writer)
+   {
+     this(writer, 2, 10);
+   }
+ 
+   Debug(int maxdepth)
+   {
+     this(System.err, maxdepth, 10);
+   }
+ 
+   Debug()
+   {
+     this(System.err);
+   }
+   
+   private final void indent()
+   {
+     for (int i = 0; i < depth; i++)
+       p.print("  ");
+   }
+ 
+   private final java.util.IdentityHashMap h = 
+     new java.util.IdentityHashMap();
+ 
+   private static native Field[] getDeclaredFields(Class c);
+   private static native Object getField(Object o, Field f);
+   private static native long getAddr(Object o);
+ 
+   // Return an array containing all the fields of a class and its
+   // superclasses.
+   private Field[] internalGetFields(Class c)
+   {
+     HashSet set = new HashSet();
+     set.addAll(Arrays.asList(getDeclaredFields(c)));
+     Class[] interfaces = c.getInterfaces();
+     for (int i = 0; i < interfaces.length; i++)
+       set.addAll(Arrays.asList(internalGetFields(interfaces[i])));
+     Class superClass = c.getSuperclass();
+     if (superClass != null)
+       set.addAll(Arrays.asList(internalGetFields(superClass)));
+     return (Field[])set.toArray(new Field[set.size()]);
+   }
+ 
+   // FIXME: We could just use getClass() here, but this is a
+   // workaround for a C++ bug that is causing getClass() to be
+   // miscompiled.
+   static private Class getItsClass(Object O)
+   {
+     return O.getClass();
+   }
+ 
+   // Print a reasonably readable textual representation of an object
+   // on our OutputStream.  Objects are only printed once, no matter
+   // how many references point to them.
+   private void print(Object O)
+   {
+     int savedDepth = depth;
+     h.put(O, O);
+     try
+       {
+ 	Class C = O.getClass();
+ 	p.print(C.getName() + "@");
+ 	p.println(Long.toHexString(getAddr(O)));
+ 
+ 	if (C.isArray())
+ 	  {
+ 	    indent(); p.println("{");
+ 	    depth++;
+ 	    indent();
+ 	    C = C.getComponentType();
+ 
+ 	    int len = Array.getLength(O);
+ 	    for (int i = 0; i < len; i++)
+ 	      {
+ 		Object thing = Array.get(O, i);
+ 		print0(thing, C);
+ 		p.print(", ");
+ 		if (i > maxArrayLength)
+ 		  {
+ 		    p.print("...");
+ 		    break;
+ 		  }
+ 	      }
+ 	    depth--;
+ 	    p.println();
+ 	    indent(); p.print("}");
+ 	    return;
+ 	  }
+ 
+ 	indent(); p.println("{");
+ 	depth++;
+ 	Field[] f = internalGetFields(C);
+ 	for (int i = 0; i < f.length; i++)
+ 	  {
+ 	    Class type = f[i].getType();
+ 	    indent(); 
+ 	    if ((f[i].getModifiers() & Modifier.STATIC) != 0)
+ 	      p.print("static ");
+ 	    p.print(type.getName() +" " +f[i].getName() + " = ");
+ 	    Object thing = getField(O, f[i]);
+ 	    print0(thing, type);
+ 	    p.println(",");
+ 	  }
+ 	depth--;
+ 	indent(); p.print("}");
+       }
+     catch (Throwable t)
+       {
+ 	p.print("error: 0x" + Long.toHexString(getAddr(O)) + ";");
+ 	depth = savedDepth;
+       }
+   }
+ 
+   private void print0(Object thing, Class C)
+   {
+     try
+       {
+ 	if (thing == null)
+ 	  {
+ 	    p.print("null");
+ 	    return;
+ 	  }
+ 	else if (C.isPrimitive())
+ 	  {
+ 	    if (getItsClass(thing) == Character.class)				
+ 	      p.print("'" + thing + "'");
+ 	    else
+ 	      p.print(thing);
+ 	    return;
+ 	  }
+ 	else if (getItsClass(thing) == String.class)
+ 	  {			  
+ 	    p.print("\"" + thing + "\"");
+ 	    return;
+ 	  }
+ 	else if (depth < maxdepth && h.get(thing) == null)
+ 	  {
+ 	    depth++;
+ 	    print(thing);
+ 	    depth--;
+ 	    return;
+ 	  }
+       }
+     catch (Throwable t)
+       {
+       }
+     
+     // The default cation: just print the address.
+     p.print("0x"+ Long.toHexString(getAddr(thing)));    
+   }
+ 
+   // Print the textual representation of an object on System.err.
+   public void write(Object O)
+   {
+     depth = 0;
+     print(O);
+     p.flush();
+   }
+ }
Index: gnu/gcj/util/natDebug.cc
===================================================================
RCS file: gnu/gcj/util/natDebug.cc
diff -N gnu/gcj/util/natDebug.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gnu/gcj/util/natDebug.cc	1 Mar 2004 20:58:43 -0000
***************
*** 0 ****
--- 1,111 ----
+ // natDebug -- C++ side of Debug
+ 
+ /* Copyright (C) 2004  Free Software Foundation
+ 
+    This file is part of libgcj.
+ 
+ This software is copyrighted work licensed under the terms of the
+ Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+ details.  */
+ 
+ #include <config.h>
+ #include <stddef.h>
+ #include <gcj/cni.h>
+ #include <gcj/field.h>
+ #include <gcj/javaprims.h>
+ #include <java/lang/reflect/Field.h>
+ #include <java/lang/Class.h>
+ #include <java/lang/Byte.h>
+ #include <java/lang/Short.h>
+ #include <java/lang/Integer.h>
+ #include <java/lang/Long.h>
+ #include <java/lang/Float.h>
+ #include <java/lang/Double.h>
+ #include <java/lang/Boolean.h>
+ #include <java/lang/Character.h>
+ #include <java/lang/IllegalArgumentException.h>
+ 
+ #include <gnu/gcj/util/Debug.h>
+ 
+ jlong 
+ gnu::gcj::util::Debug::getAddr (::java::lang::Object *o)
+ {
+   return (jlong)(size_t)o;
+ }
+ 
+ JArray< ::java::lang::reflect::Field *> *
+ gnu::gcj::util::Debug::getDeclaredFields (::java::lang::Class *c)
+ {
+   return c->getDeclaredFields (false);
+ }
+ 
+ static void *
+ ::getField (::java::lang::Object *obj, 
+ 	    ::java::lang::reflect::Field *field)
+ {
+   using namespace java::lang::reflect;
+   
+   jfieldID fld = _Jv_FromReflectedField (field);
+   _Jv_ushort flags = fld->getModifiers();
+ 
+   if (flags & Modifier::STATIC)
+     {
+       jclass fldClass = field->getDeclaringClass ();
+       JvInitClass(fldClass);
+       return (void*) fld->u.addr;
+     }
+   else
+     {
+       return (void*) ((char*) obj + fld->getOffset ());
+     }
+ }
+ 
+ ::java::lang::Object *
+ gnu::gcj::util::Debug::getField (::java::lang::Object *o, 
+ 				   ::java::lang::reflect::Field *field)
+ {
+   void *addr = ::getField (o, field);
+ 
+   jclass type = field->getType();
+   if (! type->isPrimitive ())
+     return * (jobject*) addr;
+   if (type == JvPrimClass (double))
+     return new java::lang::Double (* (jdouble*) addr);
+   if (type == JvPrimClass (float))
+     return new java::lang::Float (* (jfloat*) addr);
+   if (type == JvPrimClass (long))
+     return new java::lang::Long (* (jlong*) addr);
+   if (type == JvPrimClass (int))
+     return new java::lang::Integer (* (jint*) addr);
+   if (type == JvPrimClass (short))
+     return new java::lang::Short (* (jshort*) addr);
+   if (type == JvPrimClass (byte))
+     return new java::lang::Byte (* (jbyte*) addr);
+   if (type == JvPrimClass (char))
+     return new java::lang::Character (* (jchar*) addr);
+   if (type == JvPrimClass (boolean))
+     {
+       _Jv_InitClass (&java::lang::Boolean::class$);
+       if (* (jboolean*) addr)
+ 	return java::lang::Boolean::TRUE;
+       else
+ 	return java::lang::Boolean::FALSE;
+     }
+   throw new java::lang::IllegalArgumentException;
+ }
+ 
+ /* A simple method of printing an object that can be called from a
+    debugger.  */
+ extern "C"
+ void
+ _Jv_Debug (void *p)
+ {
+   (new ::gnu::gcj::util::Debug ())->write ((jobject)p);
+ }
+ 
+ extern "C"
+ void
+ _Jv_DeepDebug (void *p, int depth)
+ {
+   (new ::gnu::gcj::util::Debug (depth))->write ((jobject)p);
+ }


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