diff options
Diffstat (limited to 'libjava/gnu/gcj/util')
-rw-r--r-- | libjava/gnu/gcj/util/Debug.h | 57 | ||||
-rw-r--r-- | libjava/gnu/gcj/util/Debug.java | 226 | ||||
-rw-r--r-- | libjava/gnu/gcj/util/GCInfo.h | 45 | ||||
-rw-r--r-- | libjava/gnu/gcj/util/GCInfo.java | 79 | ||||
-rw-r--r-- | libjava/gnu/gcj/util/UtilPermission.h | 32 | ||||
-rw-r--r-- | libjava/gnu/gcj/util/UtilPermission.java | 20 | ||||
-rw-r--r-- | libjava/gnu/gcj/util/natDebug.cc | 118 | ||||
-rw-r--r-- | libjava/gnu/gcj/util/natGCInfo.cc | 458 |
8 files changed, 1035 insertions, 0 deletions
diff --git a/libjava/gnu/gcj/util/Debug.h b/libjava/gnu/gcj/util/Debug.h new file mode 100644 index 000000000..3ad59ef6d --- /dev/null +++ b/libjava/gnu/gcj/util/Debug.h @@ -0,0 +1,57 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __gnu_gcj_util_Debug__ +#define __gnu_gcj_util_Debug__ + +#pragma interface + +#include <java/lang/Object.h> +#include <gcj/array.h> + +extern "Java" +{ + namespace gnu + { + namespace gcj + { + namespace util + { + class Debug; + } + } + } +} + +class gnu::gcj::util::Debug : public ::java::lang::Object +{ + +public: // actually package-private + Debug(::java::io::PrintStream *, jint, jint, jboolean); + Debug(::java::io::PrintStream *); + Debug(jint, jboolean); + Debug(jint); + Debug(); +private: + void indent(); + static JArray< ::java::lang::reflect::Field * > * getDeclaredFields(::java::lang::Class *); + static ::java::lang::Object * getField(::java::lang::Object *, ::java::lang::reflect::Field *); + static jlong getAddr(::java::lang::Object *); + JArray< ::java::lang::reflect::Field * > * internalGetFields(::java::lang::Class *); + static ::java::lang::Class * getItsClass(::java::lang::Object *); + void print(::java::lang::Object *); + void print0(::java::lang::Object *, ::java::lang::Class *); +public: + virtual void write(::java::lang::Object *); +private: + ::java::io::PrintStream * __attribute__((aligned(__alignof__( ::java::lang::Object)))) p; + jint maxdepth; + jint maxArrayLength; + jboolean printStaticFields; + jint depth; + ::java::util::IdentityHashMap * h; +public: + static ::java::lang::Class class$; +}; + +#endif // __gnu_gcj_util_Debug__ diff --git a/libjava/gnu/gcj/util/Debug.java b/libjava/gnu/gcj/util/Debug.java new file mode 100644 index 000000000..d19ab694d --- /dev/null +++ b/libjava/gnu/gcj/util/Debug.java @@ -0,0 +1,226 @@ +/* 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 final boolean printStaticFields; + private int depth; + + Debug(PrintStream writer, int maxdepth, int maxArrayLength, boolean printStaticFields) + { + p = writer; + this.maxdepth = maxdepth; + this.maxArrayLength = maxArrayLength; + this.printStaticFields = printStaticFields; + } + + Debug(PrintStream writer) + { + this(writer, 0, 10, false); + } + + Debug(int maxdepth, boolean printStaticFields) + { + this(new PrintStream + (new FileOutputStream(FileDescriptor.err), true), + maxdepth, + maxdepth > 0 ? 1000 : 10, printStaticFields); + } + + Debug(int maxdepth) + { + this(maxdepth, false); + } + + Debug() + { + this(0, false); + } + + 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 = getItsClass(O); + 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++; + if (C == java.lang.Class.class) + { + indent(); + p.println ("class = " + O.toString() + ","); + } + else if (C == java.lang.reflect.Field.class) + { + indent(); + p.println ("<field> = \"" + O.toString() + "\","); + } + else if (C == java.lang.String.class) + { + indent(); + p.println ("<string> = \"" + O.toString() + "\","); + } + Field[] f = internalGetFields(C); + for (int i = 0; i < f.length; i++) + { + Class type = f[i].getType(); + boolean isStatic = (f[i].getModifiers() & Modifier.STATIC) != 0; + + if (isStatic && ! printStaticFields) + continue; + + indent(); + if (isStatic) + 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 == gnu.gcj.RawData.class || + C == gnu.gcj.RawDataManaged.class) + { + } + 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 action: 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(); + } +} diff --git a/libjava/gnu/gcj/util/GCInfo.h b/libjava/gnu/gcj/util/GCInfo.h new file mode 100644 index 000000000..06e0dd0d0 --- /dev/null +++ b/libjava/gnu/gcj/util/GCInfo.h @@ -0,0 +1,45 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __gnu_gcj_util_GCInfo__ +#define __gnu_gcj_util_GCInfo__ + +#pragma interface + +#include <java/lang/Object.h> +extern "Java" +{ + namespace gnu + { + namespace gcj + { + namespace util + { + class GCInfo; + } + } + } +} + +class gnu::gcj::util::GCInfo : public ::java::lang::Object +{ + + GCInfo(); + static void checkPermission(); +public: + static void dump(::java::lang::String *); +private: + static void dump0(::java::lang::String *); +public: + static void enumerate(::java::lang::String *); +private: + static void enumerate0(::java::lang::String *); +public: + static void setOOMDump(::java::lang::String *); +private: + static void setOOMDump0(::java::lang::String *); +public: + static ::java::lang::Class class$; +}; + +#endif // __gnu_gcj_util_GCInfo__ diff --git a/libjava/gnu/gcj/util/GCInfo.java b/libjava/gnu/gcj/util/GCInfo.java new file mode 100644 index 000000000..73f4718f9 --- /dev/null +++ b/libjava/gnu/gcj/util/GCInfo.java @@ -0,0 +1,79 @@ +/* GCInfo.java -- Support for creating heap dumps. + Copyright (C) 2007 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. */ + +package gnu.gcj.util; + +public class GCInfo +{ + private GCInfo() + { + } + + /** + * @throws SecurityException if there is a SecurityManager installed + * and UtilPermission("dumpHeap") is not granted. + */ + private static void checkPermission() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new UtilPermission("dumpHeap")); + } + + + /** + * Dump a description of the heap state. + * + * @param namePrefix The filename prefix for the dump files. + * + * @throws SecurityException if there is a SecurityManager installed + * and UtilPermission("dumpHeap") is not granted. + */ + public static synchronized void dump(String name) + { + checkPermission(); + dump0(name); + } + + private static native void dump0(String name); + + + /** + * Create a heap dump. + * + * @param namePrefix The filename prefix for the dump files. + * + * @throws SecurityException if there is a SecurityManager installed + * and UtilPermission("dumpHeap") is not granted. + */ + public static synchronized void enumerate(String namePrefix) + { + checkPermission(); + enumerate0(namePrefix); + } + + private static native void enumerate0(String namePrefix); + + /** + * Cause a heap dump if out-of-memory condition occurs. + * + * @param namePrefix The filename prefix for the dump files. If + * null no dumps are created. + * + * @throws SecurityException if there is a SecurityManager installed + * and UtilPermission("dumpHeap") is not granted. + */ + public static synchronized void setOOMDump(String namePrefix) + { + checkPermission(); + setOOMDump0(namePrefix); + } + + private static native void setOOMDump0(String namePrefix); +} diff --git a/libjava/gnu/gcj/util/UtilPermission.h b/libjava/gnu/gcj/util/UtilPermission.h new file mode 100644 index 000000000..4c7b22671 --- /dev/null +++ b/libjava/gnu/gcj/util/UtilPermission.h @@ -0,0 +1,32 @@ + +// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*- + +#ifndef __gnu_gcj_util_UtilPermission__ +#define __gnu_gcj_util_UtilPermission__ + +#pragma interface + +#include <java/security/BasicPermission.h> +extern "Java" +{ + namespace gnu + { + namespace gcj + { + namespace util + { + class UtilPermission; + } + } + } +} + +class gnu::gcj::util::UtilPermission : public ::java::security::BasicPermission +{ + +public: + UtilPermission(::java::lang::String *); + static ::java::lang::Class class$; +}; + +#endif // __gnu_gcj_util_UtilPermission__ diff --git a/libjava/gnu/gcj/util/UtilPermission.java b/libjava/gnu/gcj/util/UtilPermission.java new file mode 100644 index 000000000..1ea4cb716 --- /dev/null +++ b/libjava/gnu/gcj/util/UtilPermission.java @@ -0,0 +1,20 @@ +/* GCInfo.java -- Support for creating heap dumps. + Copyright (C) 2007 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. */ + +package gnu.gcj.util; + +import java.security.BasicPermission; + +public class UtilPermission extends BasicPermission +{ + public UtilPermission(String name) + { + super(name); + } +} diff --git a/libjava/gnu/gcj/util/natDebug.cc b/libjava/gnu/gcj/util/natDebug.cc new file mode 100644 index 000000000..e2631b14a --- /dev/null +++ b/libjava/gnu/gcj/util/natDebug.cc @@ -0,0 +1,118 @@ +// 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); +} + +extern "C" +void +_Jv_StaticDeepDebug (void *p, int depth) +{ + (new ::gnu::gcj::util::Debug (depth, true))->write ((jobject)p); +} diff --git a/libjava/gnu/gcj/util/natGCInfo.cc b/libjava/gnu/gcj/util/natGCInfo.cc new file mode 100644 index 000000000..a5936174d --- /dev/null +++ b/libjava/gnu/gcj/util/natGCInfo.cc @@ -0,0 +1,458 @@ +/* natGCInfo.cc -- Native portion of support for creating heap dumps. + Copyright (C) 2007 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 <gcj/cni.h> + +#include <gnu/gcj/util/GCInfo.h> + +#ifdef HAVE_PROC_SELF_MAPS +// +// If /proc/self/maps does not exist we assume we are doomed and do nothing. +// +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +// +// Boehm GC includes. +// +#ifdef PACKAGE_NAME +#undef PACKAGE_NAME +#endif + +#ifdef PACKAGE_STRING +#undef PACKAGE_STRING +#endif + +#ifdef PACKAGE_TARNAME +#undef PACKAGE_TARNAME +#endif + +#ifdef PACKAGE_VERSION +#undef PACKAGE_VERSION +#endif + +#ifdef TRUE +#undef TRUE +#endif + +#ifdef FALSE +#undef FALSE +#endif + +extern "C" { +#include "private/dbg_mlc.h" + int GC_n_set_marks(hdr* hhdr); + ptr_t GC_clear_stack(ptr_t p); + extern int GC_gcj_kind; + extern int GC_gcj_debug_kind; +} + +#endif + +#ifdef HAVE_PROC_SELF_MAPS + +static int gc_ok = 1; + +struct gc_debug_info +{ + int used; + int free; + int wasted; + int blocks; + FILE* fp; +}; + +static void +GC_print_debug_callback(hblk *h, word user_data) +{ + hdr *hhdr = HDR(h); + size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz); + + gc_debug_info *pinfo = (gc_debug_info *)user_data; + + fprintf(pinfo->fp, "ptr = %#lx, kind = %d, size = %zd, marks = %d\n", + (unsigned long)h, hhdr->hb_obj_kind, bytes, GC_n_set_marks(hhdr)); +} + +/* + this next section of definitions shouldn't really be here. + copied from boehmgc/allchblk.c +*/ + +# define UNIQUE_THRESHOLD 32 +# define HUGE_THRESHOLD 256 +# define FL_COMPRESSION 8 +# define N_HBLK_FLS (HUGE_THRESHOLD - UNIQUE_THRESHOLD)/FL_COMPRESSION \ + + UNIQUE_THRESHOLD +#ifndef USE_MUNMAP +extern "C" { + extern word GC_free_bytes[N_HBLK_FLS+1]; +} +#endif + +# ifdef USE_MUNMAP +# define IS_MAPPED(hhdr) (((hhdr) -> hb_flags & WAS_UNMAPPED) == 0) +# else /* !USE_MMAP */ +# define IS_MAPPED(hhdr) 1 +# endif /* USE_MUNMAP */ + +static void +GC_print_hblkfreelist_file(FILE *fp) +{ + struct hblk * h; + word total_free = 0; + hdr * hhdr; + word sz; + int i; + + fprintf(fp, "---------- Begin free map ----------\n"); + for (i = 0; i <= N_HBLK_FLS; ++i) + { + h = GC_hblkfreelist[i]; +#ifdef USE_MUNMAP + if (0 != h) + fprintf (fp, "Free list %ld:\n", (unsigned long)i); +#else + if (0 != h) + fprintf (fp, "Free list %ld (Total size %ld):\n", + (unsigned long)i, + (unsigned long)GC_free_bytes[i]); +#endif + while (h != 0) + { + hhdr = HDR(h); + sz = hhdr -> hb_sz; + fprintf (fp, "\t0x%lx size %lu ", (unsigned long)h, + (unsigned long)sz); + total_free += sz; + + if (GC_is_black_listed (h, HBLKSIZE) != 0) + fprintf (fp, "start black listed\n"); + else if (GC_is_black_listed(h, hhdr -> hb_sz) != 0) + fprintf (fp, "partially black listed\n"); + else + fprintf (fp, "not black listed\n"); + + h = hhdr -> hb_next; + } + } +#ifndef USE_MUNMAP + if (total_free != GC_large_free_bytes) + { + fprintf (fp, "GC_large_free_bytes = %lu (INCONSISTENT!!)\n", + (unsigned long) GC_large_free_bytes); + } +#endif + fprintf (fp, "Total of %lu bytes on free list\n", (unsigned long)total_free); + fprintf (fp, "---------- End free map ----------\n"); +} + +static int GC_dump_count = 1; + +static void +GC_print_debug_info_file(FILE* fp) +{ + gc_debug_info info; + + memset(&info, 0, sizeof info); + info.fp = fp; + + if (gc_ok) + GC_gcollect(); + fprintf(info.fp, "---------- Begin block map ----------\n"); + GC_apply_to_all_blocks(GC_print_debug_callback, (word)(void*)(&info)); + //fprintf(fp, "#Total used %d free %d wasted %d\n", info.used, info.free, info.wasted); + //fprintf(fp, "#Total blocks %d; %dK bytes\n", info.blocks, info.blocks*4); + fprintf(info.fp, "---------- End block map ----------\n"); + + //fprintf(fp, "\n***Free blocks:\n"); + //GC_print_hblkfreelist(); +} + +namespace +{ + class __attribute__ ((visibility ("hidden"))) GC_enumerator + { + public: + GC_enumerator(const char *name); + void enumerate(); + private: + FILE* fp; + int bytes_fd; + + void print_address_map(); + void enumerate_callback(struct hblk *h); + static void enumerate_callback_adaptor(struct hblk *h, word dummy); + }; +} + +GC_enumerator::GC_enumerator(const char *name) +{ + bytes_fd = -1; + fp = fopen (name, "w"); + if (!fp) + { + printf ("GC_enumerator failed to open [%s]\n", name); + return; + } + printf ("GC_enumerator saving summary to [%s]\n", name); + + // open heap file + char bytes_name[strlen(name) + 10]; + sprintf (bytes_name, "%s.bytes", name); + bytes_fd = open (bytes_name, O_CREAT|O_TRUNC|O_WRONLY, 0666); + if (bytes_fd <= 0) + { + printf ("GC_enumerator failed to open [%s]\n", bytes_name); + return; + } + printf ("GC_enumerator saving heap contents to [%s]\n", bytes_name); +} + +/* + sample format of /proc/self/maps + + 0063b000-00686000 rw-p 001fb000 03:01 81993 /avtrex/bin/dumppropapp + 00686000-0072e000 rwxp 00000000 00:00 0 + + These are parsed below as: + start -end xxxx xxxxxxxx a:b xxxxxxxxxxxxxxx + +*/ + + +void +GC_enumerator::print_address_map() +{ + FILE* fm; + char buffer[128]; + + fprintf(fp, "---------- Begin address map ----------\n"); + + fm = fopen("/proc/self/maps", "r"); + if (fm == NULL) + { +#ifdef HAVE_STRERROR_R + if (0 == strerror_r (errno, buffer, sizeof buffer)) + fputs (buffer, fp); +#else + fputs (strerror (errno), fp); +#endif + } + else + { + while (fgets (buffer, sizeof buffer, fm) != NULL) + { + fputs (buffer, fp); + char *dash = strchr(buffer, '-'); + char *colon = strchr(buffer, ':'); + if (dash && colon && ((ptrdiff_t)strlen(buffer) > (colon - buffer) + 2)) + { + char *endp; + unsigned long start = strtoul(buffer, NULL, 16); + unsigned long end = strtoul(dash + 1, &endp, 16); + unsigned long a = strtoul(colon - 2, NULL, 16); + unsigned long b = strtoul(colon + 1, NULL, 16); + // If it is an anonymous mapping 00:00 and both readable + // and writeable then dump the contents of the mapping + // to the bytes file. Each block has a header of three + // unsigned longs: + // 0 - The number sizeof(unsigned long) to detect endianness and + // structure layout. + // 1 - The offset in VM. + // 2 - The Length in bytes. + // Followed by the bytes. + if (!a && !b && endp < colon && 'r' == endp[1] && 'w' == endp[2]) + { + unsigned long t = sizeof(unsigned long); + write(bytes_fd, (void*)&t, sizeof(t)); + write(bytes_fd, (void*)&start, sizeof(start)); + t = end - start; + write(bytes_fd, (void*)&t, sizeof(t)); + write(bytes_fd, (void*)start, (end - start)); + } + } + } + fclose(fm); + } + fprintf(fp, "---------- End address map ----------\n"); + fflush(fp); +} + +void +GC_enumerator::enumerate() +{ + print_address_map(); + fprintf(fp, "---------- Begin object map ----------\n"); + if (gc_ok) + GC_gcollect(); + GC_apply_to_all_blocks(enumerate_callback_adaptor, + (word)(void*)(this)); + fprintf(fp, "---------- End object map ----------\n"); + fflush(fp); + + GC_print_debug_info_file(fp); + fflush(fp); + GC_print_hblkfreelist_file(fp); + fflush(fp); + + close(bytes_fd); + fclose(fp); + + GC_clear_stack(0); +} + +void +GC_enumerator::enumerate_callback_adaptor(struct hblk *h, + word dummy) +{ + GC_enumerator* pinfo = (GC_enumerator*)dummy; + pinfo->enumerate_callback(h); +} + +void +GC_enumerator::enumerate_callback(struct hblk *h) +{ + hdr * hhdr = HDR(h); + size_t bytes = WORDS_TO_BYTES(hhdr->hb_sz); + int i; + + for (i = 0; i == 0 || (i + bytes <= HBLKSIZE); i += bytes) + { + int inUse = mark_bit_from_hdr(hhdr,BYTES_TO_WORDS(i)); // in use + char *ptr = (char*)h+i; // address + int kind = hhdr->hb_obj_kind; // kind + void *klass = 0; + void *data = 0; + if (kind == GC_gcj_kind + || kind == GC_gcj_debug_kind + || kind == GC_gcj_debug_kind+1) + { + void* v = *(void **)ptr; + if (v) + { + klass = *(void **)v; + data = *(void **)(ptr + sizeof(void*)); + } + } + if (inUse) + fprintf (fp, "used = %d, ptr = %#lx, size = %zd, kind = %d, " + "klass = %#lx, data = %#lx\n", + inUse, (unsigned long)ptr, bytes, kind, + (unsigned long)klass, (unsigned long)data); + } +} + +/* + * Fill in a char[] with low bytes of the string characters. These + * methods may be called while an OutOfMemoryError is being thrown, so + * we cannot call nice java methods to get the encoding of the string. + */ +static void +J2A(::java::lang::String* str, char *dst) +{ + jchar * pchars = JvGetStringChars(str); + jint len = str->length(); + int i; + for (i=0; i<len; i++) + dst[i] = (char)pchars[i]; + dst[i] = 0; +} + +void +::gnu::gcj::util::GCInfo::dump0 (::java::lang::String * name) +{ + char n[name->length() + 1]; + J2A(name, n); + + char temp[name->length() + 20]; + sprintf(temp, "%s%03d", n, GC_dump_count++); + FILE* fp = fopen(temp, "w"); + + GC_print_debug_info_file(fp); + + fclose(fp); +} + +void +::gnu::gcj::util::GCInfo::enumerate0 (::java::lang::String * name) +{ + char n[name->length() + 1]; + J2A(name, n); + char temp[name->length() + 20]; + sprintf(temp, "%s%03d", n, GC_dump_count++); + + GC_enumerator x(temp); + x.enumerate(); +} + +static char *oomDumpName = NULL; + +static void * +nomem_handler(size_t size) +{ + if (oomDumpName) + { + char temp[strlen(oomDumpName) + 20]; + sprintf(temp, "%s%03d", oomDumpName, GC_dump_count++); + printf("nomem_handler(%zd) called\n", size); + gc_ok--; + GC_enumerator x(temp); + x.enumerate(); + gc_ok++; + } + return (void*)0; +} + +void +::gnu::gcj::util::GCInfo::setOOMDump0 (::java::lang::String * name) +{ + char *oldName = oomDumpName; + oomDumpName = NULL; + free (oldName); + + if (NULL == name) + return; + + char *n = (char *)malloc(name->length() + 1); + + J2A(name, n); + oomDumpName = n; + GC_oom_fn = nomem_handler; +} + +#else // HAVE_PROC_SELF_MAPS + +void +::gnu::gcj::util::GCInfo::dump0 (::java::lang::String * name) +{ + // Do nothing if dumping not supported. +} + +void +::gnu::gcj::util::GCInfo::enumerate0 (::java::lang::String * name) +{ + // Do nothing if dumping not supported. +} + +void +::gnu::gcj::util::GCInfo::setOOMDump0 (::java::lang::String * name) +{ + // Do nothing if dumping not supported. +} + +#endif // HAVE_PROC_SELF_MAPS + |