aboutsummaryrefslogtreecommitdiff
path: root/libjava/gnu
diff options
context:
space:
mode:
authorDavid Daney <daney@gcc.gnu.org>2007-02-15 17:25:24 +0000
committerDavid Daney <daney@gcc.gnu.org>2007-02-15 17:25:24 +0000
commit7f40378f06a5723ede9c8abc23775cadcdd0037c (patch)
treeecd80f4d6cba05c29ed9420459814c84387b36bf /libjava/gnu
parent31429fbc3c70716cb375dc73d1d151ed769d945e (diff)
downloadgcc-7f40378f06a5723ede9c8abc23775cadcdd0037c.zip
gcc-7f40378f06a5723ede9c8abc23775cadcdd0037c.tar.gz
gcc-7f40378f06a5723ede9c8abc23775cadcdd0037c.tar.bz2
Make-lang.in (JAVA_MANFILES): Add doc/gc-analyze.1.
gcc/java: 2007-02-15 David Daney <ddaney@avtrex.com> * Make-lang.in (JAVA_MANFILES): Add doc/gc-analyze.1. (java.maintainer-clean):Add gc-analyze.1. (.INTERMEDIATE): Add gc-analyze.pod. (gc-analyze.pod): New rule. (java.install-man): Install gc-analyze.1 * gcj.texi: Add new section for the gc-analyze program. libjava: 2007-02-15 Johannes Schmidt <jschmidt@avtrex.com> David Daney <ddaney@avtrex.com> * configure.ac: Create vm-tools-packages file. Add gnu/gcj/tools/gc_analyze to standard.omit and vm-tools-packages. Check for /proc/self/maps. * Makefile.am (bin_PROGRAMS): Added gc-analyze. (gc_analyze_SOURCES): New. (gc_analyze_LDFLAGS): New. (gc_analyze_LINK): New. (gc_analyze_LDADD): New. (gc_analyze_DEPENDENCIES): New. (nat_source_files): Add gnu/gcj/util/natGCInfo.cc. * Makefile.in: Regenerated. * configure: Regenerated. * include/config.h.in: Regenerated. * sources.am: Regenerated. * scripts/makemake.tcl: Don't include gc-analyze classes in libgcj. * gnu/gcj/tools/gc_analyze/SymbolLookup.java: New. * gnu/gcj/tools/gc_analyze/ObjectMap.java: New. * gnu/gcj/tools/gc_analyze/MemoryMap.java: New. * gnu/gcj/tools/gc_analyze/SymbolTable.java: New. * gnu/gcj/tools/gc_analyze/BlockMap.java: New. * gnu/gcj/tools/gc_analyze/BytePtr.java: New. * gnu/gcj/tools/gc_analyze/ItemList.java: New. * gnu/gcj/tools/gc_analyze/ToolPrefix.java: New. * gnu/gcj/tools/gc_analyze/MemoryAnalyze.java: New. * gnu/gcj/util/GCInfo.java: New. * gnu/gcj/util/GCInfo.h: New. * gnu/gcj/util/natGCInfo.cc: New. * gnu/gcj/util/UtilPermission.java: New. * gnu/gcj/util/UtilPermission.h: New. * classpath/tools/gnu/gcj/tools/gc_analyze/SymbolTable.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/ObjectMap$ObjectItem.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryMap$RangeComparator.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/BlockMap$PtrMarks.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryMap$Range.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/BlockMap.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/BytePtr.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryAnalyze$SubstringComparator.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/ItemList.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/ToolPrefix.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryAnalyze.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryAnalyze$1$Info.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryAnalyze$1.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryAnalyze$2.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryAnalyze$3.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryAnalyze$4.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryAnalyze$OptionParser.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/BlockMap$SizeKind.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/SymbolLookup.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/ObjectMap.class: New. * classpath/tools/gnu/gcj/tools/gc_analyze/MemoryMap.class: New. * classpath/lib/gnu/gcj/util/GCInfo.class: New. * classpath/lib/gnu/gcj/util/UtilPermission.class: New. libjava/classpath: 2007-02-15 David Daney <ddaney@avtrex.com> * tools/Makefile.am (TOOLS_ZIP): Add classes from vm-tools-packages. * tools/Makefile.in: Regenerated. From-SVN: r122007
Diffstat (limited to 'libjava/gnu')
-rw-r--r--libjava/gnu/gcj/tools/gc_analyze/BlockMap.java218
-rw-r--r--libjava/gnu/gcj/tools/gc_analyze/BytePtr.java115
-rw-r--r--libjava/gnu/gcj/tools/gc_analyze/ItemList.java72
-rw-r--r--libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java458
-rw-r--r--libjava/gnu/gcj/tools/gc_analyze/MemoryMap.java359
-rw-r--r--libjava/gnu/gcj/tools/gc_analyze/ObjectMap.java140
-rw-r--r--libjava/gnu/gcj/tools/gc_analyze/SymbolLookup.java112
-rw-r--r--libjava/gnu/gcj/tools/gc_analyze/SymbolTable.java198
-rw-r--r--libjava/gnu/gcj/tools/gc_analyze/ToolPrefix.java45
-rw-r--r--libjava/gnu/gcj/util/GCInfo.h45
-rw-r--r--libjava/gnu/gcj/util/GCInfo.java79
-rw-r--r--libjava/gnu/gcj/util/UtilPermission.h32
-rw-r--r--libjava/gnu/gcj/util/UtilPermission.java20
-rw-r--r--libjava/gnu/gcj/util/natGCInfo.cc454
14 files changed, 2347 insertions, 0 deletions
diff --git a/libjava/gnu/gcj/tools/gc_analyze/BlockMap.java b/libjava/gnu/gcj/tools/gc_analyze/BlockMap.java
new file mode 100644
index 0000000..6e7adae
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gc_analyze/BlockMap.java
@@ -0,0 +1,218 @@
+/* BlockMap.java -- Container for information on GC maintained memory blocks.
+ 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.tools.gc_analyze;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.TreeMap;
+
+class BlockMap
+{
+ static final int HBLKSIZE = 4096;
+
+ class SizeKind implements Comparable<SizeKind>
+ {
+ int size;
+ int kind;
+
+ public SizeKind(int size, int kind)
+ {
+ this.size = size;
+ this.kind = kind;
+ }
+
+ public int compareTo(SizeKind b)
+ {
+ if (this.size != b.size)
+ return this.size - b.size;
+ return this.kind - b.kind;
+ }
+ }
+
+ class PtrMarks
+ {
+ long ptr;
+ int marks;
+
+ public PtrMarks(long ptr, int marks)
+ {
+ this.ptr = ptr;
+ this.marks = marks;
+ }
+ }
+
+ private TreeMap<SizeKind, ArrayList<PtrMarks>> map =
+ new TreeMap<SizeKind, ArrayList<PtrMarks>>();
+
+ public BlockMap(BufferedReader reader) throws IOException
+ {
+ for (;;)
+ {
+ String s = reader.readLine();
+ if (s == null)
+ break;
+ if (s.charAt(0) == '#')
+ continue;
+ if (s.indexOf("Begin block map") >= 0)
+ {
+ for (;;)
+ {
+ s = reader.readLine();
+ if (s.charAt(0) == '#')
+ continue;
+ if (s.indexOf("End block map") >= 0)
+ return;
+ String[] items = s.split(",");
+ long ptr = 0;
+ int kind = 0, size = 0, marks = 0;
+ for (int i=0; i<items.length; i++)
+ {
+ String[] x = items[i].split(" ");
+ String last = x[x.length - 1];
+ switch (i)
+ {
+ case 0:
+ ptr = MemoryMap.parseHexLong(last.substring(2));
+ break;
+ case 1:
+ kind = Integer.parseInt(last);
+ break;
+ case 2:
+ size = Integer.parseInt(last);
+ break;
+ case 3:
+ marks = Integer.parseInt(last);
+ break;
+ }
+ }
+ SizeKind sk = new SizeKind(size, kind);
+ ArrayList<PtrMarks> m = map.get(sk);
+ if (m == null)
+ {
+ m = new ArrayList<PtrMarks>();
+ map.put(sk, m);
+ }
+ PtrMarks pm = new PtrMarks(ptr, marks);
+ m.add(pm);
+ } // inner loop
+ } // started inner loop
+ } // outer loop - finding begin
+ } // memoryMap
+
+ public void dump()
+ {
+ System.out.println();
+ System.out.println();
+ System.out.println("*** Used Blocks ***\n");
+ System.out.println();
+ System.out.println(" Size Kind Blocks Used Free Wasted");
+ System.out.println("------- ------------- ------- ---------- ---------- -------");
+
+ int total_blocks = 0, total_used = 0, total_free = 0, total_wasted = 0;
+
+ for (Map.Entry<SizeKind, ArrayList<PtrMarks>> me : map.entrySet())
+ {
+ SizeKind sk = me.getKey();
+
+ System.out.println(MemoryAnalyze.format(sk.size, 7) + " "
+ + MemoryAnalyze.kindToName(sk.kind));
+
+ int sub_blocks = 0, sub_used = 0, sub_free = 0, sub_wasted = 0;
+ int sub_count = 0;
+
+ ArrayList<PtrMarks> v = me.getValue();
+
+ for (PtrMarks pm : v)
+ {
+ int bytes = sk.size;
+ int blocks = (sk.size + HBLKSIZE - 1) / HBLKSIZE;
+ int used;
+ int free;
+ int wasted;
+
+ if (bytes < HBLKSIZE)
+ {
+ used = bytes * pm.marks;
+ free = bytes * (HBLKSIZE / bytes - pm.marks);
+ wasted = HBLKSIZE - HBLKSIZE / bytes * bytes;
+ }
+ else
+ {
+ if (pm.marks != 0)
+ {
+ used = bytes;
+ free = 0;
+ wasted = (bytes + HBLKSIZE - 1)
+ / HBLKSIZE * HBLKSIZE - used;
+ }
+ else
+ {
+ used = 0;
+ free = bytes;
+ wasted = 0;
+ }
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(blocks, 5));
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(used, 9));
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(free, 9));
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(wasted, 9));
+ System.out.println(sb);
+
+ sub_blocks += blocks;
+ sub_used += used;
+ sub_free += free;
+ sub_wasted += wasted;
+ sub_count++;
+
+ total_blocks += blocks;
+ total_used += used;
+ total_free += free;
+ total_wasted += wasted;
+ } // blocks with size/kind
+ if (sub_count > 1)
+ {
+ System.out.println(
+ " ------- ---------- ---------- -------");
+ StringBuilder sb = new StringBuilder();
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(sub_blocks, 5));
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(sub_used, 9));
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(sub_free, 9));
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(sub_wasted, 9));
+ System.out.println(sb);
+ }
+ } // size/kind
+
+ System.out.println("------- ------------- ------- ---------- ---------- -------");
+ StringBuilder sb = new StringBuilder();
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(total_blocks, 5));
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(total_used, 9));
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(total_free, 9));
+ sb.append(" ");
+ sb.append(MemoryAnalyze.format(total_wasted, 9));
+ System.out.println(sb);
+ System.out.println("Total bytes = "
+ + MemoryAnalyze.format(total_blocks * HBLKSIZE, 10));
+ }
+}
diff --git a/libjava/gnu/gcj/tools/gc_analyze/BytePtr.java b/libjava/gnu/gcj/tools/gc_analyze/BytePtr.java
new file mode 100644
index 0000000..4afceee
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gc_analyze/BytePtr.java
@@ -0,0 +1,115 @@
+/* BytePtr.java -- Container for bytes from a memory image.
+ 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.tools.gc_analyze;
+
+import java.nio.ByteBuffer;
+
+public class BytePtr
+{
+ ByteBuffer content;
+ int wordSize;
+
+ BytePtr(ByteBuffer b, int ws)
+ {
+ content = b;
+ wordSize = ws;
+ }
+
+ public int getsize()
+ {
+ return content.limit();
+ }
+
+ public int getByte(int offset)
+ {
+ return content.get(offset);
+ }
+
+ public int getInt(int n)
+ {
+ return content.getInt(n * 4);
+ }
+
+ public int getShort(int n)
+ {
+ return content.getShort(n * 2);
+ }
+
+ public long getWord(int n)
+ {
+ if (4 == wordSize)
+ return 0xffffffffL & content.getInt(n * 4);
+ else
+ return content.getLong(n * 8);
+ }
+
+ public int intsPerWord()
+ {
+ return (4 == wordSize) ? 1 : 2;
+ }
+
+ public BytePtr getRegion(int offset, int size)
+ {
+ int oldLimit = content.limit();
+ content.position(offset);
+ content.limit(offset + size);
+ ByteBuffer n = content.slice();
+ content.position(0);
+ content.limit(oldLimit);
+
+ return new BytePtr(n, wordSize);
+ }
+
+ public void setInt(int a, int n)
+ {
+ content.putInt(a * 4, n);
+ }
+
+ public void dump()
+ {
+ // 38 5a f4 2a 50 bd 04 10 10 00 00 00 0e 00 00 00 8Z.*P...........
+ int i;
+ StringBuilder b = new StringBuilder(67);
+ for (i = 0; i < 66; i++)
+ b.append(' ');
+ b.append('\n');
+
+ i = 0;
+ do
+ {
+ for (int j = 0; j < 16; j++)
+ {
+ int k = i + j;
+
+ if (k < content.limit())
+ {
+ int v = 0xff & getByte(k);
+ // hex
+ int v1 = v/16;
+ b.setCharAt(j * 3 + 0,
+ (char)(v1 >= 10 ? 'a' - 10 + v1 : v1 + '0'));
+ v1 = v % 16;
+ b.setCharAt(j * 3 + 1,
+ (char)(v1 >= 10 ? 'a' - 10 + v1 : v1 + '0'));
+ // ascii
+ b.setCharAt(j + 50, (char)((v >= 32 && v <= 127) ? v: '.'));
+ }
+ else
+ {
+ b.setCharAt(j * 3 + 0, ' ');
+ b.setCharAt(j * 3 + 1, ' ');
+ b.setCharAt(j + 50, ' ');
+ }
+ }
+ i += 16;
+ System.out.print(b);
+ } while (i < content.limit());
+ }
+}
diff --git a/libjava/gnu/gcj/tools/gc_analyze/ItemList.java b/libjava/gnu/gcj/tools/gc_analyze/ItemList.java
new file mode 100644
index 0000000..7912beb
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gc_analyze/ItemList.java
@@ -0,0 +1,72 @@
+/* ItemList.java -- Maps all objects keyed by their addresses.
+ 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.tools.gc_analyze;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+class ItemList
+{
+ public ItemList()
+ {
+ }
+
+ private TreeMap<Long, HashMap<ObjectMap.ObjectItem, Integer>> map;
+
+ public void add(ObjectMap.ObjectItem item)
+ {
+ if (map == null)
+ map = new TreeMap<Long, HashMap<ObjectMap.ObjectItem, Integer>>();
+ Long x = new Long(item.klass);
+ HashMap<ObjectMap.ObjectItem, Integer> list = map.get(x);
+ if (list == null)
+ {
+ list = new HashMap<ObjectMap.ObjectItem, Integer>();
+ map.put(x, list);
+ }
+ Integer count = list.get(item);
+ if (count == null)
+ list.put(item, new Integer(1));
+ else
+ list.put(item, new Integer(count.intValue() + 1));
+ }
+
+ void dump(String title, SymbolLookup lookup) throws IOException
+ {
+ if (map == null)
+ return;
+ System.out.println(title);
+ for (Map.Entry<Long, HashMap<ObjectMap.ObjectItem, Integer>> me :
+ map.entrySet())
+ {
+ HashMap<ObjectMap.ObjectItem, Integer> list = me.getValue();
+ boolean first = true;
+
+ for (Map.Entry<ObjectMap.ObjectItem, Integer> me2 : list.entrySet())
+ {
+ ObjectMap.ObjectItem item = me2.getKey();
+ Integer count = me2.getValue();
+ if (first)
+ {
+ String name =
+ MemoryAnalyze.getSymbolPretty(lookup, item, false);
+ System.out.println(" " + name + ":");
+ first = false;
+ }
+ System.out.print(" 0x" + Long.toHexString(item.ptr));
+ if (count.intValue() != 1)
+ System.out.print(" * " + count);
+ System.out.println();
+ }
+ }
+ }
+}
diff --git a/libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java b/libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java
new file mode 100644
index 0000000..d56a71d
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java
@@ -0,0 +1,458 @@
+/* MemoryAnalyze.java -- Analyzes a libgcj heap dump.
+ 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.tools.gc_analyze;
+
+import gnu.classpath.tools.getopt.FileArgumentCallback;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+class MemoryAnalyze
+{
+ public MemoryAnalyze()
+ {
+ }
+
+ private static NumberFormat numberFormat;
+ private static boolean verbose;
+ static String format(long number, int digits)
+ {
+ if (numberFormat == null)
+ {
+ numberFormat = NumberFormat.getNumberInstance();
+ numberFormat.setGroupingUsed(true);
+ }
+ String temp = numberFormat.format(number);
+ int spaces = digits - temp.length();
+ if (spaces < 0)
+ spaces = 0;
+ return " ".substring(0,spaces) + temp;
+ }
+
+ static void sorted_report(String description,
+ int total_space,
+ ArrayList<String> list,
+ Comparator<String> comparator)
+ {
+ System.out.println("*** " + description + " ***");
+ System.out.println();
+ System.out.println(" Total Size Count Size Description");
+ System.out.println("-------------- ----- -------- -----------------------------------");
+ Collections.sort(list, comparator);
+ for (Iterator it = list.iterator(); it.hasNext(); )
+ {
+ String v = (String)it.next();
+ System.out.println(stripend(v));
+ }
+ System.out.println("-------------- ----- -------- -----------------------------------");
+ System.out.println(format(total_space, 14));
+ System.out.println();
+ System.out.println();
+ }
+
+ private static String stripend(String s)
+ {
+ int n = s.lastIndexOf(" /");
+ if (n > 0)
+ return s.substring(0,n);
+ return s;
+ }
+
+ static class SubstringComparator implements Comparator<String>
+ {
+ private int begin, end;
+ private boolean reverse;
+
+ SubstringComparator(int begin, int end, boolean reverse)
+ {
+ this.begin = begin;
+ this.end = end;
+ this.reverse = reverse;
+ }
+
+ public int compare(String s1, String s2)
+ {
+ if (end == 0)
+ s1 = s1.substring(begin);
+ else
+ s1 = s1.substring(begin, end);
+
+ if (end == 0)
+ s2 = s2.substring(begin);
+ else
+ s2 = s2.substring(begin, end);
+ int i = s1.compareTo(s2);
+ if (reverse)
+ return -i;
+ return i;
+ }
+ }
+
+ static class OptionParser extends Parser
+ {
+ int filesFound;
+
+ OptionParser()
+ {
+ super("gc-analyze",
+ "gc-analyze (" + System.getProperty("java.vm.version") + ")");
+
+ add(new Option('d',
+ "Directory containing runtime objects",
+ "directory")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ ToolPrefix.pathPrefix = argument;
+ }
+ });
+
+ add(new Option('p',
+ "Binary tool prefix, prepended to nm and readelf to "
+ + "obtain target specific versions of these commands",
+ "prefix")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ ToolPrefix.toolPrefix = argument;
+ }
+ });
+
+ add(new Option("verbose", 'v',
+ "Verbose output; requires filename.bytes")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+
+ setHeader("usage: gc-analyze [-v] [-p tool-prefix] [-d <directory>] "
+ + "filename");
+ }
+
+ protected void validate() throws OptionException
+ {
+ if (filesFound != 1)
+ throw new OptionException("Must specify exactly one filename");
+ }
+
+ public String[] parse(String[] inArgs)
+ {
+ final ArrayList<String> fileResult = new ArrayList<String>();
+ parse(inArgs, new FileArgumentCallback()
+ {
+ public void notifyFile(String fileArgument)
+ {
+ filesFound++;
+ fileResult.add(fileArgument);
+ }
+ });
+ return fileResult.toArray(new String[1]);
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ class Info
+ {
+ int size;
+ int count;
+ }
+ int total_space = 0;
+
+ Parser optionParser = new OptionParser();
+
+ String rest[] = optionParser.parse(args);
+
+ String filename = rest[0];
+
+ try
+ {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
+ SymbolLookup lookup = new SymbolLookup(reader, filename + ".bytes");
+ ObjectMap objectMap = new ObjectMap(reader);
+ BlockMap blockMap = new BlockMap(reader);
+ reader.close();
+
+ // add info to item(s)
+ // add item.klass
+ for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
+ {
+ ObjectMap.ObjectItem item = me.getValue();
+
+ // try to get a klass (happens with intern'ed strings...)
+ if (item.klass==0)
+ {
+ BytePtr p = lookup.getBytePtr(item.ptr, item.size);
+ if (p!=null)
+ {
+ long vtable = p.getWord(0);
+ String sym =
+ lookup.getSymbolViaVtable(vtable - 2 * lookup.memoryMap.wordSize);
+ if (sym != null)
+ {
+ item.typeName = SymbolTable.demangleVTName(sym);
+ }
+ else if (vtable != 0)
+ {
+ // get klass from vtable
+ p = lookup.getBytePtr(vtable,
+ lookup.memoryMap.wordSize);
+ if (p != null)
+ {
+ long klass = p.getWord(0);
+ item.klass = klass;
+ }
+ }
+ }
+ }
+
+ // figure out strings
+ String class_name;
+ if (null == item.typeName)
+ {
+ class_name =
+ MemoryAnalyze.getSymbolPretty(lookup, item, false);
+ item.typeName = class_name;
+ }
+ else
+ {
+ class_name = item.typeName;
+ }
+ System.out.print("class_name=[" + class_name + "]");
+
+ if (class_name.compareTo("_ZTVN4java4lang6StringE")==0
+ || class_name.compareTo("java.lang.String")==0)
+ {
+ BytePtr p = lookup.getBytePtr(item.ptr, item.size);
+ long data = p.getWord(1);
+ int boffset = p.getInt(2 * p.intsPerWord());
+ int count = p.getInt(1 + 2 * p.intsPerWord());
+ int hash = p.getInt(2 + 2 * p.intsPerWord());
+ BytePtr chars = lookup.getBytePtr(data+boffset, count * 2);
+ StringBuffer sb = new StringBuffer(count);
+ for (int qq = 0; qq<count; qq++)
+ sb.append((char)chars.getShort(qq));
+ int newhash = sb.toString().hashCode();
+ if (newhash!=hash)
+ {
+ p.setInt(4, newhash);
+ }
+
+ item.string = sb.toString();
+ System.out.println(" value = \"" + item.string + "\"");
+ if (data != item.ptr)
+ {
+ ObjectMap.ObjectItem next = objectMap.get(data);
+ if (next != null)
+ next.stringData = true;
+ else
+ System.out.println("String [" + item.string + "] at "
+ + Long.toHexString(item.ptr)
+ + " can't find array at "
+ + Long.toHexString(data));
+ }
+ }
+ else if (null != item.string)
+ System.out.println(" value = \"" + item.string + "\"");
+ else
+ System.out.println();
+ }
+
+
+ HashMap<String, Info> map = new HashMap<String, Info>();
+ for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
+ {
+ ObjectMap.ObjectItem item = me.getValue();
+ String name = getSymbolPretty(lookup, item, true);
+ Info info = map.get(name);
+ if (info == null)
+ {
+ info = new Info();
+ info.count = 0;
+ info.size = item.size;
+ map.put(name, info);
+ }
+ info.count++;
+ total_space += item.size;
+ }
+
+ ArrayList<String> list = new ArrayList<String>();
+ for (Iterator it = map.entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry me = (Map.Entry)it.next();
+ String name = (String)me.getKey();
+ Info info = (Info)me.getValue();
+
+ StringBuffer sb = new StringBuffer();
+ sb.append(format(info.count * info.size * 100 / total_space,
+ 3));
+ sb.append("%");
+ sb.append(format(info.count * info.size, 10));
+ sb.append(" = ");
+ sb.append(format(info.count, 7));
+ sb.append(" * ");
+ sb.append(format(info.size, 9));
+ sb.append(" - ");
+ sb.append(name);
+ list.add(sb.toString());
+ }
+
+ sorted_report("Memory Usage Sorted by Total Size",
+ total_space, list, new SubstringComparator(5,14,true));
+ sorted_report("Memory Usage Sorted by Description",
+ total_space, list, new SubstringComparator(39,0,false));
+ sorted_report("Memory Usage Sorted by Count",
+ total_space, list, new SubstringComparator(17,25,true));
+ sorted_report("Memory Usage Sorted by Size",
+ total_space, list, new SubstringComparator(28,37,true));
+
+ blockMap.dump();
+
+ // dump raw memory
+ if (verbose)
+ {
+ // analyze references
+ for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
+ {
+ long ptr = me.getKey();
+ ObjectMap.ObjectItem item = me.getValue();
+ BytePtr p = lookup.getBytePtr(ptr, item.size);
+ if (p == null)
+ System.out.println("can't find ptr 0x"
+ + Long.toHexString(ptr));
+ else if (item.kind != 0) // not GC_PTRFREE
+ for (int i = 1;
+ i < item.size / lookup.memoryMap.wordSize; i++)
+ {
+ long maybe_ptr = p.getWord(i);
+ ObjectMap.ObjectItem item2 = objectMap.get(maybe_ptr);
+ if (item2 != null)
+ {
+ item2.pointed_by.add(item);
+ item.points_to.add(item2);
+ }
+ }
+ }
+ System.out.println();
+ System.out.println("*** All Objects ***");
+ System.out.println();
+
+ for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
+ {
+ long ptr = me.getKey();
+ ObjectMap.ObjectItem item = me.getValue();
+ String name = getSymbolPretty(lookup, item, false);
+ System.out.print("0x" + Long.toHexString(ptr) + " - " + name
+ + " (" + item.size + ")");
+ if (item.string != null)
+ System.out.println(" \"" + item.string + "\"");
+ else
+ System.out.println();
+
+ BytePtr p = lookup.getBytePtr(ptr, item.size);
+
+ if (p == null)
+ System.out.println(
+ "can't find memory; recently allocated from free list?");
+ else
+ p.dump();
+
+ item.points_to.dump(" points to:", lookup);
+ item.pointed_by.dump(" pointed to by:", lookup);
+ System.out.println();
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static String kindToName(int kind)
+ {
+ String name;
+ switch (kind)
+ {
+ case 0:
+ name = "GC_PTRFREE";
+ break;
+ case 1:
+ name = "GC_NORMAL";
+ break;
+ case 2:
+ name = "GC_UNCOLLECTABLE";
+ break;
+ case 3:
+ name = "GC_AUUNCOLLCTABLE";
+ break;
+ case 4:
+ name = "(Java)";
+ break;
+ case 5:
+ name = "(Java Debug)";
+ break;
+ case 6:
+ name = "(Java Array)";
+ break;
+ default:
+ name = "(Kind " + kind + ")";
+ break;
+ }
+ return name;
+ }
+
+ public static String getSymbolPretty(SymbolLookup lookup,
+ ObjectMap.ObjectItem item,
+ boolean bsize)
+ throws IOException
+ {
+
+ String name = item.typeName;
+
+ if (name == null)
+ name = lookup.getSymbol(item.klass);
+
+ if (name == null)
+ {
+ String v = lookup.decodeUTF8(item.ptr, item.size);
+ if (null != v)
+ {
+ name = "UTF8Const";
+ item.string = v;
+ }
+ }
+
+ if (name == null)
+ {
+ name = kindToName(item.kind);
+ }
+ if (item.kind==6)
+ name += "[" + format(item.data, 0) + "]";
+ if (bsize)
+ name = name + " / " + format(item.size, 7);
+ return name;
+ }
+}
diff --git a/libjava/gnu/gcj/tools/gc_analyze/MemoryMap.java b/libjava/gnu/gcj/tools/gc_analyze/MemoryMap.java
new file mode 100644
index 0000000..1bc06d5
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gc_analyze/MemoryMap.java
@@ -0,0 +1,359 @@
+/* MemoryMap.java -- Maps address ranges to their data.
+ 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.tools.gc_analyze;
+
+import java.io.BufferedReader;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Reads /proc/self/maps output from dump file.
+ * Creates map of <filename> to Range.
+ *
+ * Returns filename given address.
+ * Returns offset given address.
+ * Returns BytePtr given address.
+ *
+ */
+class MemoryMap
+{
+ static class RangeComparator implements Comparator<Range>
+ {
+ public int compare(Range r1, Range r2)
+ {
+ if (r2.end == 0 && r1.end != 0)
+ return -compare(r2, r1);
+
+ if (r1.begin < r2.begin)
+ return -1;
+ else if (r1.begin >= r2.end)
+ return 1;
+ else
+ return 0;
+ }
+ }
+
+ static class Range
+ {
+ long begin;
+ long end;
+
+ long offset;
+ String filename;
+ Range()
+ {
+ }
+
+ Range(long b, long e, String s, long o)
+ {
+ begin = b;
+ end = e;
+ filename = s;
+ offset = o;
+ }
+ }
+
+ /**
+ * Parse the string as an unsigned hexadecimal number. This is
+ * similar to Long.parseInt(s,16), but without the restriction that
+ * values that have the sign bit set not being allowed.
+ *
+ * @param s the number as a String.
+ * @return the number.
+ */
+ static long parseHexLong(String s)
+ {
+ if (s.length() > 16)
+ throw new NumberFormatException();
+ long r = 0;
+ for (int i = 0; i < s.length(); i++)
+ {
+ int digit = 0;
+ char c = s.charAt(i);
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ digit = c - '0';
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ digit = 10 + c - 'a';
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ digit = 10 + c - 'A';
+ break;
+ default:
+ throw new NumberFormatException();
+ }
+ r = (r << 4) + digit;
+ }
+ return r;
+ }
+
+ // String filename -> Range
+ TreeSet<Range> map = new TreeSet<Range>(new RangeComparator());
+ HashMap<String, SymbolTable> symbolTables =
+ new HashMap<String, SymbolTable>();
+ ByteOrder byteOrder;
+ int wordSize;
+
+ public MemoryMap(BufferedReader reader,
+ String rawFileName) throws IOException
+ {
+ FileChannel raw = (new RandomAccessFile(rawFileName, "r")).getChannel();
+ ByteBuffer buf = ByteBuffer.allocate(8);
+ raw.read(buf);
+ if (buf.hasRemaining())
+ {
+ raw.close();
+ throw new EOFException();
+ }
+ buf.flip();
+ wordSize = buf.get();
+
+ if (wordSize == 8 || wordSize == 4)
+ byteOrder = ByteOrder.LITTLE_ENDIAN;
+ else
+ {
+ byteOrder = ByteOrder.BIG_ENDIAN;
+ buf.rewind();
+ wordSize = buf.getInt();
+ if (0 == wordSize)
+ wordSize = buf.getInt();
+ }
+ switch (wordSize)
+ {
+ case 4:
+ case 8:
+ break;
+ default:
+ throw new IOException("Bad .bytes file header");
+ }
+ buf = ByteBuffer.allocate(3 * wordSize);
+ buf.order(byteOrder);
+ raw.position(0L);
+
+ for(;;)
+ {
+ // Read the block header.
+ buf.clear();
+ if (-1 == raw.read(buf))
+ {
+ //EOF
+ raw.close();
+ break;
+ }
+ if (buf.hasRemaining())
+ {
+ raw.close();
+ throw new EOFException();
+ }
+ buf.flip();
+ long dummy
+ = (wordSize == 4) ? (buf.getInt() & 0xffffffffL) : buf.getLong();
+ if (dummy != wordSize)
+ throw new IOException("Bad .bytes file header");
+ long start
+ = wordSize == 4 ? (buf.getInt() & 0xffffffffL) : buf.getLong();
+ long length
+ = wordSize == 4 ? (buf.getInt() & 0xffffffffL) : buf.getLong();
+ if (length < 0L)
+ throw new IOException("Bad .bytes file header");
+
+ long currentPos = raw.position();
+ raw.position(currentPos + length);
+
+ Range range = new Range(start, start + length,
+ rawFileName, currentPos);
+ map.add(range);
+ }
+
+ for (;;)
+ {
+ String s = reader.readLine();
+ if (s == null)
+ break;
+ if (s.indexOf("Begin address map") >= 0)
+ {
+ for (;;)
+ {
+ s = reader.readLine();
+ if (s.indexOf("End address map") >= 0)
+ {
+ dump();
+ return;
+ }
+ int endOfAddress = s.indexOf('-');
+ long address = parseHexLong(s.substring(0, endOfAddress));
+ int endOfAddress2 = s.indexOf(' ', endOfAddress + 1);
+ long address2 = parseHexLong(s.substring(endOfAddress + 1,
+ endOfAddress2));
+ int endOfOffset = s.indexOf(' ', endOfAddress2 + 6);
+ long offset;
+ try
+ {
+ offset = parseHexLong(s.substring(endOfAddress2 + 6,
+ endOfOffset));
+ }
+ catch (Exception e)
+ {
+ offset = 0;
+ }
+ int end = s.indexOf('/');
+
+ if (end > 0)
+ {
+ String file = s.substring(end);
+ if (file.startsWith("/dev/"))
+ continue;
+
+ Range r = new Range(address, address2, file, offset);
+ if (offset == 0)
+ {
+ // Read the file's symbol table
+ try
+ {
+ File f = ToolPrefix.fileForName(file);
+ if (f != null)
+ {
+ SymbolTable st = new SymbolTable(f.getPath());
+ if (st.loadAddr != address)
+ st.relocation = address - st.loadAddr;
+ symbolTables.put(file, st);
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ map.add(r);
+ }
+ } // inner loop
+ } // started inner loop
+ } // outer loop - finding begin
+ } // memoryMap
+
+
+ public void dump()
+ {
+ System.out.println("MemoryMap:");
+ for (Range r : map)
+ {
+ System.out.println(Long.toHexString(r.begin) + "-"
+ + Long.toHexString(r.end) + " -> "
+ + r.filename + " offset "
+ + Long.toHexString(r.offset));
+ }
+ }
+
+ Range getRange(long addr)
+ {
+ Range r = new Range();
+ r.begin = addr;
+ SortedSet<Range> t = map.tailSet(r);
+ if (t.isEmpty())
+ return null;
+ Range c = t.first();
+ if (c.begin <= addr && addr < c.end)
+ return c;
+ return null;
+ }
+
+ String getFile(long addr)
+ {
+ Range r = getRange(addr);
+ if (null != r)
+ return r.filename;
+ return null;
+ }
+
+ long getOffset(long addr)
+ {
+ Range r = getRange(addr);
+ if (null != r)
+ return r.offset;
+ return 0L;
+ }
+
+ /**
+ * @return BytePtr which includes given address.
+ */
+ BytePtr getBytePtr(long addr, int length) throws IOException
+ {
+ Range r = getRange(addr);
+
+ if (null == r)
+ return null;
+
+ File f = ToolPrefix.fileForName(r.filename);
+ if (null == f)
+ return null;
+
+ if (addr + length > r.end)
+ length = (int)(r.end - addr);
+
+ ByteBuffer b = ByteBuffer.allocate(length);
+ b.order(byteOrder);
+
+ FileChannel fc = (new RandomAccessFile(f, "r")).getChannel();
+ fc.position(r.offset + addr - r.begin);
+ int nr = fc.read(b);
+ fc.close();
+ if (nr != length)
+ return null;
+ b.flip();
+ return new BytePtr(b, wordSize);
+ }
+
+ public String getSymbol(long addr)
+ {
+ Range r = getRange(addr);
+
+ if (r == null)
+ return null;
+
+ SymbolTable st = symbolTables.get(r.filename);
+ if (st == null)
+ return null;
+
+ // Apply relocation
+ addr -= st.relocation;
+
+ return st.getSymbol(addr);
+ }
+}
diff --git a/libjava/gnu/gcj/tools/gc_analyze/ObjectMap.java b/libjava/gnu/gcj/tools/gc_analyze/ObjectMap.java
new file mode 100644
index 0000000..b55034b
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gc_analyze/ObjectMap.java
@@ -0,0 +1,140 @@
+/* ObjectMap.java -- Contains a map of all objects keyed by their addresses.
+ 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.tools.gc_analyze;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+
+class ObjectMap implements Iterable<Map.Entry<Long, ObjectMap.ObjectItem>>
+{
+
+ class ObjectItem
+ {
+ int used;
+ int size;
+ int kind;
+ long klass;
+ long data;
+ long ptr;
+ String typeName;
+ String string; // only for string objects
+ boolean stringData; // character array pointed to by a string
+ ObjectItem reference; // object at reference points to this
+
+ ItemList points_to = new ItemList();
+ ItemList pointed_by = new ItemList();
+ }
+
+ private TreeMap<Long, ObjectItem> map = new TreeMap<Long, ObjectItem>();
+
+ public Iterator<Map.Entry<Long, ObjectItem>> iterator()
+ {
+ return map.entrySet().iterator();
+ }
+
+ public ObjectItem get(long ptr)
+ {
+ ObjectItem item = map.get(ptr);
+ return item;
+ }
+
+ public ObjectMap(BufferedReader reader) throws IOException
+ {
+ outer_loop:
+ for (;;)
+ {
+ String s = reader.readLine();
+ if (s == null)
+ break;
+ if (s.indexOf("Begin object map") >= 0)
+ {
+ for (;;)
+ {
+ s = reader.readLine();
+ if (s.indexOf("End object map") >= 0)
+ break outer_loop;
+ String[] items = s.split(",");
+ ObjectItem item = new ObjectItem();
+ long ptr = 0;
+ for (int i=0; i<items.length; i++)
+ {
+ String[] x = items[i].split(" ");
+ String last = x[x.length-1];
+ switch (i)
+ {
+ case 0:
+ item.used = Integer.parseInt(last);
+ break;
+ case 1:
+ ptr = MemoryMap.parseHexLong(last.substring(2));
+ break;
+ case 2:
+ item.size = Integer.parseInt(last);
+ break;
+ case 3:
+ item.kind = Integer.parseInt(last);
+ break;
+ case 4:
+ if (last.length() > 1)
+ item.klass =
+ MemoryMap.parseHexLong(last.substring(2));
+ else
+ item.klass = Integer.parseInt(last,16);
+ break;
+ case 5:
+ try
+ {
+ item.data =
+ Integer.parseInt(last.substring(2), 16);
+ }
+ catch (Exception e)
+ {
+ item.data = 0;
+ }
+ break;
+ }
+ }
+ item.ptr = ptr;
+ map.put(ptr, item);
+ } // inner loop
+ } // started inner loop
+ } // outer loop - finding begin
+ for (Map.Entry<Long, ObjectItem> me : this)
+ {
+ ObjectItem item = me.getValue();
+ if (item.data != 0)
+ {
+ // see if data is a pointer to a block
+ ObjectItem referenced = map.get(item.data);
+ if (referenced != null)
+ {
+ referenced.reference = item;
+ }
+ }
+ }
+ } // memoryMap
+
+ public void dump()
+ {
+ for (Map.Entry<Long, ObjectItem> me : this)
+ {
+ long ptr = me.getKey();
+ ObjectItem item = me.getValue();
+ System.out.println("ptr = " + Long.toHexString(ptr)
+ + ", size = " + item.size
+ + ", klass = " + Long.toHexString(item.klass)
+ + ", kind = " + item.kind
+ + ", data = " + item.data);
+ }
+ }
+}
diff --git a/libjava/gnu/gcj/tools/gc_analyze/SymbolLookup.java b/libjava/gnu/gcj/tools/gc_analyze/SymbolLookup.java
new file mode 100644
index 0000000..b3963d8
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gc_analyze/SymbolLookup.java
@@ -0,0 +1,112 @@
+/* SymbolLookup.java -- Finds class names by analyzing memory.
+ 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.tools.gc_analyze;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+
+class SymbolLookup
+{
+ MemoryMap memoryMap;
+
+ public SymbolLookup(BufferedReader reader,
+ String rawFileName)
+ throws IOException
+ {
+ memoryMap = new MemoryMap(reader, rawFileName);
+ }
+
+ public String decodeUTF8(long address) throws IOException
+ {
+ return decodeUTF8(address, -1);
+ }
+
+ public String decodeUTF8(long address, int limit) throws IOException
+ {
+ if (address == 0)
+ return null;
+
+ BytePtr utf8 = memoryMap.getBytePtr(address, 64);
+
+ if (utf8 == null)
+ return null;
+
+ int len = utf8.getShort(1);
+ int hash16 = utf8.getShort(0) & 0xffff;
+
+ if (len <= 0 || (limit > 0 && len > (limit - 4)))
+ return null;
+
+ if (len > utf8.getsize() + 4)
+ utf8 = memoryMap.getBytePtr(address, len + 4);
+
+ if (utf8 == null)
+ return null;
+
+ StringBuilder sb = new StringBuilder(len);
+ int pos = 4;
+ len += 4;
+
+ while (pos < len)
+ {
+ int f = utf8.getByte(pos++);
+ if ((f & 0x80) == 0)
+ {
+ sb.append((char)f);
+ }
+ else if ((f & 0xe0) == 0xc0)
+ {
+ int s = utf8.getByte(pos++);
+ char c = (char)(((f & 0x1f) << 6) | (s & 0x80));
+ sb.append(c);
+ }
+ else if ((f & 0xe0) == 0xe0)
+ {
+ int s = utf8.getByte(pos++);
+ int t = utf8.getByte(pos++);
+ char c = (char)(((f & 0x0f) << 12)
+ | ((s & 0x80) << 6) | (t & 0x80));
+ sb.append(c);
+ }
+ else
+ break; // Bad utf8
+ }
+ String rv = sb.toString();
+ if (hash16 == (rv.hashCode() & 0xffff))
+ return rv;
+ else
+ return null;
+ }
+
+ public String getSymbolViaVtable(long address) throws IOException
+ {
+ return memoryMap.getSymbol(address);
+ }
+
+ public String getSymbol(long address) throws IOException
+ {
+ String symbol = memoryMap.getSymbol(address);
+ if (null != symbol)
+ return symbol;
+
+ BytePtr klass = memoryMap.getBytePtr(address, 3 * memoryMap.wordSize);
+ if (klass == null)
+ return null;
+
+ long nameUTF8p = klass.getWord(2);
+
+ return decodeUTF8(nameUTF8p);
+ }
+
+ BytePtr getBytePtr(long addr, int length) throws IOException
+ {
+ return memoryMap.getBytePtr(addr, length);
+ }
+}
diff --git a/libjava/gnu/gcj/tools/gc_analyze/SymbolTable.java b/libjava/gnu/gcj/tools/gc_analyze/SymbolTable.java
new file mode 100644
index 0000000..eb5df76
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gc_analyze/SymbolTable.java
@@ -0,0 +1,198 @@
+/* SymbolTable.java -- Maintains a mapping of addresses to names.
+ 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.tools.gc_analyze;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class SymbolTable
+{
+ // Long address->String name
+ private HashMap<Long, String> map = new HashMap<Long, String>();
+
+ // Reverse
+ // String name -> Long address
+ // used for RelocateImage
+ private HashMap<String, Long> reverse = new HashMap<String, Long>();
+
+ long loadAddr;
+ long relocation;
+
+ static Matcher interestingSymbol =
+ Pattern.compile("^([0-9a-fA-F]+)\\s+\\S+\\s+(_Z\\S+)").matcher("");
+ static Matcher readelfLoadMatcher =
+ Pattern.compile("^\\s+LOAD\\s+(\\S+)\\s+(\\S+)\\s.*").matcher("");
+
+ public SymbolTable(String filename) throws IOException
+ {
+ Process p = Runtime.getRuntime().exec(ToolPrefix.toolPrefix
+ + "nm " + filename);
+ InputStream es = p.getErrorStream();
+ InputStream is = p.getInputStream();
+
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ int count = 0;
+
+ String line;
+ while ((line = reader.readLine()) != null)
+ {
+ interestingSymbol.reset(line);
+ if (interestingSymbol.matches())
+ {
+ try
+ {
+ String name = interestingSymbol.group(2);
+ String addr = interestingSymbol.group(1);
+ if (name.startsWith("_ZTVN") || name.endsWith("6class$E"))
+ {
+ long address = MemoryMap.parseHexLong(addr);
+ Long l = new Long(address);
+ map.put(l, name);
+ count++;
+ reverse.put(name, l);
+ }
+ }
+ catch (NumberFormatException e)
+ {
+ // ignore it
+ }
+ }
+ }
+ es.close();
+ is.close();
+ p.destroy();
+
+ if (count > 0)
+ {
+ // Assume nm read some symbols from it and that
+ // readelf can tell us something about how it is loaded.
+ p = Runtime.getRuntime().exec(ToolPrefix.toolPrefix
+ + "readelf -l " + filename);
+ es = p.getErrorStream();
+ is = p.getInputStream();
+
+ reader = new BufferedReader(new InputStreamReader(is));
+ while ((line = reader.readLine()) != null)
+ {
+ readelfLoadMatcher.reset(line);
+ if (readelfLoadMatcher.matches())
+ {
+ loadAddr
+ = Long.decode(readelfLoadMatcher.group(2)).longValue();
+ break;
+ }
+ }
+ es.close();
+ is.close();
+ p.destroy();
+ }
+
+ System.out.println(ToolPrefix.toolPrefix + "nm " + filename
+ + " -> " + count + " symbols");
+ }
+
+ public static void main(String args[])
+ {
+ try
+ {
+ SymbolTable st = new SymbolTable(args[0]);
+ st.dump();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ public static String demangleVTName(String n)
+ {
+ if (n.startsWith("_ZTVN") && n.endsWith("E"))
+ return demangle(n.substring(5, n.length() - 1));
+ else
+ return null;
+ }
+
+ public void dump()
+ {
+ for (Map.Entry<Long, String> me : map.entrySet())
+ {
+ long address = me.getKey();
+ String symbol = me.getValue();
+ System.out.println(Long.toHexString(address) + " -> " + symbol);
+ if (symbol.startsWith("_ZN") && symbol.endsWith("6class$E"))
+ {
+ System.out.println(" Class: "
+ + demangle(symbol.substring(3, symbol.length()
+ - 8)));
+ }
+ else if (symbol.startsWith("_ZTVN") && symbol.endsWith("E"))
+ {
+ System.out.println(" VT: "
+ + demangle(symbol.substring(5, symbol.length()
+ - 1)));
+ }
+ }
+ }
+
+ private static String demangle(String symbol)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (int i=0; i<symbol.length(); )
+ {
+ int l = 0;
+ while (i < symbol.length())
+ {
+ int d = symbol.charAt(i);
+ if (d < '0' || d > '9')
+ break;
+ l = 10 * l + (d - '0');
+ i++;
+ }
+ if (l == 0)
+ break;
+ // copy
+ if (sb.length() > 0)
+ sb.append('.');
+ while (l > 0 && i < symbol.length())
+ {
+ sb.append(symbol.charAt(i));
+ l--;
+ i++;
+ }
+ }
+ return sb.toString();
+ }
+
+ public String getSymbol(long address)
+ {
+ String symbol = map.get(address);
+ if (symbol == null)
+ return null;
+
+ if (symbol.startsWith("_ZN") && symbol.endsWith("6class$E"))
+ symbol = demangle(symbol.substring(3, symbol.length() - 8));
+ return symbol;
+ }
+
+ // will return -1 if not found
+ public long getAddress(String symbol)
+ {
+ Long address = reverse.get(symbol);
+ if (address == null)
+ return -1;
+ return address.longValue();
+ }
+}
diff --git a/libjava/gnu/gcj/tools/gc_analyze/ToolPrefix.java b/libjava/gnu/gcj/tools/gc_analyze/ToolPrefix.java
new file mode 100644
index 0000000..e8d73ae
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gc_analyze/ToolPrefix.java
@@ -0,0 +1,45 @@
+/* ToolPrefix.java -- Container of the toolPrefix String.
+ 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.tools.gc_analyze;
+
+import java.io.File;
+
+class ToolPrefix
+{
+ /**
+ * Private constructor. No creation allowed. This class has
+ * Static methods only.
+ */
+ private ToolPrefix()
+ {
+ }
+
+ static String toolPrefix = "";
+
+ static String pathPrefix = "";
+
+ static File fileForName(String filename)
+ {
+ File f = new File(pathPrefix + filename);
+ if (!f.canRead())
+ {
+ // Try it without the prefix.
+ f = new File(filename);
+ if (!f.canRead())
+ {
+ // Try to find it in the current directory.
+ f = new File(f.getName());
+ if (!f.canRead())
+ return null;
+ }
+ }
+ return f;
+ }
+}
diff --git a/libjava/gnu/gcj/util/GCInfo.h b/libjava/gnu/gcj/util/GCInfo.h
new file mode 100644
index 0000000..06e0dd0
--- /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 0000000..73f4718
--- /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 0000000..4c7b226
--- /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 0000000..1ea4cb7
--- /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/natGCInfo.cc b/libjava/gnu/gcj/util/natGCInfo.cc
new file mode 100644
index 0000000..7e5c6fb
--- /dev/null
+++ b/libjava/gnu/gcj/util/natGCInfo.cc
@@ -0,0 +1,454 @@
+/* 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;
+
+typedef 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)
+ {
+ if (0 == strerror_r (errno, buffer, sizeof buffer))
+ fputs (buffer, fp);
+ }
+ 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", temp, 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
+