From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001
From: upstream source tree <ports@midipix.org>
Date: Sun, 15 Mar 2015 20:14:05 -0400
Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified
 gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream
 tarball.

downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.

if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
---
 libjava/gnu/gcj/tools/gc_analyze/BlockMap.java     | 218 +++++++++
 libjava/gnu/gcj/tools/gc_analyze/BytePtr.java      | 115 +++++
 libjava/gnu/gcj/tools/gc_analyze/ItemList.java     |  72 +++
 .../gnu/gcj/tools/gc_analyze/MemoryAnalyze.java    | 458 +++++++++++++++++
 libjava/gnu/gcj/tools/gc_analyze/MemoryMap.java    | 359 ++++++++++++++
 libjava/gnu/gcj/tools/gc_analyze/ObjectMap.java    | 140 ++++++
 libjava/gnu/gcj/tools/gc_analyze/SymbolLookup.java | 112 +++++
 libjava/gnu/gcj/tools/gc_analyze/SymbolTable.java  | 198 ++++++++
 libjava/gnu/gcj/tools/gc_analyze/ToolPrefix.java   |  45 ++
 libjava/gnu/gcj/tools/gcj_dbtool/Fileset.h         |  42 ++
 libjava/gnu/gcj/tools/gcj_dbtool/Main.h            |  55 +++
 libjava/gnu/gcj/tools/gcj_dbtool/Main.java         | 541 +++++++++++++++++++++
 libjava/gnu/gcj/tools/gcj_dbtool/Tokenizer.h       |  40 ++
 libjava/gnu/gcj/tools/gcj_dbtool/natMain.cc        |  24 +
 14 files changed, 2419 insertions(+)
 create mode 100644 libjava/gnu/gcj/tools/gc_analyze/BlockMap.java
 create mode 100644 libjava/gnu/gcj/tools/gc_analyze/BytePtr.java
 create mode 100644 libjava/gnu/gcj/tools/gc_analyze/ItemList.java
 create mode 100644 libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java
 create mode 100644 libjava/gnu/gcj/tools/gc_analyze/MemoryMap.java
 create mode 100644 libjava/gnu/gcj/tools/gc_analyze/ObjectMap.java
 create mode 100644 libjava/gnu/gcj/tools/gc_analyze/SymbolLookup.java
 create mode 100644 libjava/gnu/gcj/tools/gc_analyze/SymbolTable.java
 create mode 100644 libjava/gnu/gcj/tools/gc_analyze/ToolPrefix.java
 create mode 100644 libjava/gnu/gcj/tools/gcj_dbtool/Fileset.h
 create mode 100644 libjava/gnu/gcj/tools/gcj_dbtool/Main.h
 create mode 100644 libjava/gnu/gcj/tools/gcj_dbtool/Main.java
 create mode 100644 libjava/gnu/gcj/tools/gcj_dbtool/Tokenizer.h
 create mode 100644 libjava/gnu/gcj/tools/gcj_dbtool/natMain.cc

(limited to 'libjava/gnu/gcj/tools')

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 000000000..6e7adae20
--- /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 000000000..4afceeeec
--- /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 000000000..7912bebca
--- /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 000000000..d56a71da3
--- /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 000000000..1bc06d584
--- /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 000000000..b55034be1
--- /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 000000000..b3963d8cf
--- /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 000000000..eb5df7641
--- /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 000000000..e8d73ae92
--- /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/tools/gcj_dbtool/Fileset.h b/libjava/gnu/gcj/tools/gcj_dbtool/Fileset.h
new file mode 100644
index 000000000..fb9b2d69e
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gcj_dbtool/Fileset.h
@@ -0,0 +1,42 @@
+
+// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-
+
+#ifndef __gnu_gcj_tools_gcj_dbtool_Fileset__
+#define __gnu_gcj_tools_gcj_dbtool_Fileset__
+
+#pragma interface
+
+#include <java/lang/Object.h>
+#include <gcj/array.h>
+
+extern "Java"
+{
+  namespace gnu
+  {
+    namespace gcj
+    {
+      namespace tools
+      {
+        namespace gcj_dbtool
+        {
+            class Fileset;
+        }
+      }
+    }
+  }
+}
+
+class gnu::gcj::tools::gcj_dbtool::Fileset : public ::java::lang::Object
+{
+
+public: // actually package-private
+  Fileset(JArray< ::java::lang::String * > *, jint, jint);
+  Fileset(::java::io::InputStream *, jchar);
+  virtual ::java::util::Iterator * iterator();
+  virtual jint size();
+  ::java::util::LinkedHashSet * __attribute__((aligned(__alignof__( ::java::lang::Object)))) files;
+public:
+  static ::java::lang::Class class$;
+};
+
+#endif // __gnu_gcj_tools_gcj_dbtool_Fileset__
diff --git a/libjava/gnu/gcj/tools/gcj_dbtool/Main.h b/libjava/gnu/gcj/tools/gcj_dbtool/Main.h
new file mode 100644
index 000000000..4052bb34c
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gcj_dbtool/Main.h
@@ -0,0 +1,55 @@
+
+// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-
+
+#ifndef __gnu_gcj_tools_gcj_dbtool_Main__
+#define __gnu_gcj_tools_gcj_dbtool_Main__
+
+#pragma interface
+
+#include <java/lang/Object.h>
+#include <gcj/array.h>
+
+extern "Java"
+{
+  namespace gnu
+  {
+    namespace gcj
+    {
+      namespace runtime
+      {
+          class PersistentByteMap;
+      }
+      namespace tools
+      {
+        namespace gcj_dbtool
+        {
+            class Fileset;
+            class Main;
+        }
+      }
+    }
+  }
+}
+
+class gnu::gcj::tools::gcj_dbtool::Main : public ::java::lang::Object
+{
+
+public:
+  Main();
+  static void main(JArray< ::java::lang::String * > *);
+private:
+  static ::java::lang::String * getDbPathTail();
+  static void insist(jboolean);
+  static void usage(::java::io::PrintStream *);
+  static ::gnu::gcj::runtime::PersistentByteMap * addJar(::java::io::File *, ::gnu::gcj::runtime::PersistentByteMap *, ::java::io::File *);
+public: // actually package-private
+  static ::gnu::gcj::runtime::PersistentByteMap * resizeMap(::gnu::gcj::runtime::PersistentByteMap *, jint, jboolean);
+  static ::java::lang::String * bytesToString(JArray< jbyte > *);
+private:
+  static ::gnu::gcj::tools::gcj_dbtool::Fileset * getFiles(JArray< ::java::lang::String * > *, jint, jboolean, jchar);
+  static jboolean verbose;
+public:
+  static ::java::lang::Class class$;
+};
+
+#endif // __gnu_gcj_tools_gcj_dbtool_Main__
diff --git a/libjava/gnu/gcj/tools/gcj_dbtool/Main.java b/libjava/gnu/gcj/tools/gcj_dbtool/Main.java
new file mode 100644
index 000000000..e5e3e44ae
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gcj_dbtool/Main.java
@@ -0,0 +1,541 @@
+/* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   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.gcj_dbtool;
+
+
+import gnu.gcj.runtime.PersistentByteMap;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.*;
+import java.util.jar.*;
+import java.security.MessageDigest;
+
+public class Main
+{
+  static private boolean verbose = false;
+
+  public static void main (String[] s)
+  {
+    boolean fileListFromStdin = false;
+    char filenameSeparator = ' ';
+
+    insist (s.length >= 1);
+
+    if (s[0].equals("-") ||
+	s[0].equals("-0"))
+      {
+	if (s[0].equals("-0"))
+	  filenameSeparator = (char)0;
+	fileListFromStdin = true;
+	String[] newArgs = new String[s.length - 1];
+	System.arraycopy(s, 1, newArgs, 0, s.length - 1);
+	s = newArgs;
+      }
+
+    if (s[0].equals("-v") || s[0].equals("--version"))
+      {
+	insist (s.length == 1);
+	System.out.println("gcj-dbtool ("
+			   + System.getProperty("java.vm.name")
+			   + ") "
+			   + System.getProperty("java.vm.version"));
+	System.out.println();
+	System.out.println("Copyright 2011 Free Software Foundation, Inc.");
+	System.out.println("This is free software; see the source for copying conditions.  There is NO");
+	System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
+	return;
+      }
+    if (s[0].equals("--help"))
+      {
+	usage(System.out);
+	return;
+      }
+
+    if (s[0].equals("-n"))
+      {
+	// Create a new database.
+	insist (s.length >= 2 && s.length <= 3);
+
+	int capacity = 32749;
+
+	if (s.length == 3)
+	  {	    
+	    capacity = Integer.parseInt(s[2]);
+
+	    if (capacity <= 2)
+	      {
+		usage(System.err);
+		System.exit(1);
+	      }
+	  }
+	    
+	try
+	  {
+	    PersistentByteMap b 
+	      = PersistentByteMap.emptyPersistentByteMap(new File(s[1]), 
+							 capacity, capacity*32);
+	  }
+	catch (Exception e)
+	  {
+	    System.err.println ("error: could not create " 
+				+ s[1] + ": " + e.toString());
+	    System.exit(2);
+	  }
+	return;
+      }
+
+    if (s[0].equals("-a") || s[0].equals("-f"))
+      {
+	// Add a jar file to a database, creating it if necessary.
+	// Copies the database, adds the jar file to the copy, and
+	// then renames the new database over the old.
+	try
+	  {
+	    insist (s.length == 4);
+	    File database = new File(s[1]);
+	    database = database.getAbsoluteFile();
+	    File jar = new File(s[2]);	
+	    PersistentByteMap map; 
+	    if (database.isFile())
+	      map = new PersistentByteMap(database, 
+					  PersistentByteMap.AccessMode.READ_ONLY);
+	    else
+	      map = PersistentByteMap.emptyPersistentByteMap(database, 
+							     100, 100*32);
+	    File soFile = new File(s[3]);
+	    if (! s[0].equals("-f") && ! soFile.isFile())
+	      throw new IllegalArgumentException(s[3] + " is not a file");
+ 	    map = addJar(jar, map, soFile);
+	  }
+	catch (Exception e)
+	  {
+	    System.err.println ("error: could not update " + s[1] 
+				+ ": " + e.toString());
+	    System.exit(2);
+	  }
+	return;
+      }
+
+    if (s[0].equals("-t"))
+      {
+	// Test
+	try
+	  {
+	    insist (s.length == 2);
+	    PersistentByteMap b 
+	      = new PersistentByteMap(new File(s[1]),
+				      PersistentByteMap.AccessMode.READ_ONLY);
+	    Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
+	
+	    while (iterator.hasNext())
+	      {
+		PersistentByteMap.MapEntry entry 
+		  = (PersistentByteMap.MapEntry)iterator.next();
+		byte[] key = (byte[])entry.getKey();
+		byte[] value = (byte[])b.get(key);
+		if (! Arrays.equals (value, (byte[])entry.getValue()))
+		  {
+		    String err 
+		      = ("Key " + bytesToString(key) + " at bucket " 
+			 + entry.getBucket());
+		  
+		    throw new RuntimeException(err);
+		  }
+	      }
+	  }
+	catch (Exception e)
+	  {
+	    e.printStackTrace();
+	    System.exit(3);
+	  }
+	return;
+      }
+	 
+    if (s[0].equals("-m"))
+      {
+	// Merge databases.
+	insist (s.length >= 3
+		|| fileListFromStdin && s.length == 2);
+	try
+	  {
+	    File database = new File(s[1]);
+	    database = database.getAbsoluteFile();
+	    File temp = File.createTempFile(database.getName(), "", 
+					    database.getParentFile());
+	    	
+	    int newSize = 0;
+	    int newStringTableSize = 0;
+	    Fileset files = getFiles(s, 2, fileListFromStdin, 
+				     filenameSeparator);
+	    PersistentByteMap[] sourceMaps 
+	      = new PersistentByteMap[files.size()];
+
+	    // Scan all the input files, calculating worst case string
+	    // table and hash table use.
+	    {
+	      Iterator it = files.iterator();
+	      int i = 0;
+	      while (it.hasNext())
+		{
+		  PersistentByteMap b 
+		    = new PersistentByteMap((File)it.next(),
+					    PersistentByteMap.AccessMode.READ_ONLY);
+		  newSize += b.size();
+		  newStringTableSize += b.stringTableSize();
+		  sourceMaps[i++] = b;
+		}
+	    }
+	    
+	    newSize *= 1.5; // Scaling the new size by 1.5 results in
+			    // fewer collisions.
+	    PersistentByteMap map 
+	      = PersistentByteMap.emptyPersistentByteMap
+	      (temp, newSize, newStringTableSize);
+
+	    for (int i = 0; i < sourceMaps.length; i++)
+	      {
+		if (verbose)
+		  System.err.println("adding " + sourceMaps[i].size() 
+				     + " elements from "
+				     + sourceMaps[i].getFile());
+		map.putAll(sourceMaps[i]);
+	      }
+	    map.close();
+	    temp.renameTo(database);
+	  }
+	catch (Exception e)
+	  {
+	    e.printStackTrace();
+	    System.exit(3);
+	  }
+	return;
+      }
+
+    if (s[0].equals("-l"))
+      {
+	// List a database.
+	insist (s.length == 2);
+	try
+	  {
+	    PersistentByteMap b 
+	      = new PersistentByteMap(new File(s[1]),
+				      PersistentByteMap.AccessMode.READ_ONLY);
+
+	    System.out.println ("Capacity: " + b.capacity());
+	    System.out.println ("Size: " + b.size());
+	    System.out.println ();
+
+	    System.out.println ("Elements: ");
+	    Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
+    
+	    while (iterator.hasNext())
+	      {
+		PersistentByteMap.MapEntry entry 
+		  = (PersistentByteMap.MapEntry)iterator.next();
+		byte[] digest = (byte[])entry.getKey();
+		System.out.print ("[" + entry.getBucket() + "] " 
+				  + bytesToString(digest)
+				  + " -> ");
+		System.out.println (new String((byte[])entry.getValue()));
+	      }
+	  }
+	catch (Exception e)
+	  {
+	    System.err.println ("error: could not list " 
+				+ s[1] + ": " + e.toString());
+	    System.exit(2);
+	  }
+	return;
+      }
+
+    if (s[0].equals("-d"))
+      {
+	// For testing only: fill the byte map with random data.
+	insist (s.length == 2);
+	try
+	  {    
+	    MessageDigest md = MessageDigest.getInstance("MD5");
+	    PersistentByteMap b 
+	      = new PersistentByteMap(new File(s[1]), 
+				      PersistentByteMap.AccessMode.READ_WRITE);
+	    int N = b.capacity();
+	    byte[] bytes = new byte[1];
+	    byte digest[] = md.digest(bytes);
+	    for (int i = 0; i < N; i++)
+	      {
+		digest = md.digest(digest);
+		b.put(digest, digest);
+	      }
+	  }
+	catch (Exception e)
+	  {
+	    e.printStackTrace();
+	    System.exit(3);
+	  }	    
+	return;
+      }
+
+    if (s[0].equals("-p"))
+      {
+	insist (s.length == 1 || s.length == 2);
+	String result;
+	
+	if (s.length == 1)
+	  result = System.getProperty("gnu.gcj.precompiled.db.path", "");
+	else 
+	  result = (s[1] 
+		    + (s[1].endsWith(File.separator) ? "" : File.separator)
+		    + getDbPathTail ());
+
+	System.out.println (result);
+	return;
+      }
+
+    usage(System.err);
+    System.exit(1);	    
+  }
+
+  private static native String getDbPathTail ();
+    
+  private static void insist(boolean ok)
+  {
+    if (! ok)
+      {
+	usage(System.err);
+	System.exit(1);
+      }	    
+  }
+
+  private static void usage(PrintStream out)
+  {
+    out.println
+      ("gcj-dbtool: Manipulate gcj map database files\n"
+       + "\n"
+       + "  Usage: \n"
+       + "    gcj-dbtool -n file.gcjdb [size]     - Create a new gcj map database\n"
+       + "    gcj-dbtool -a file.gcjdb file.jar file.so\n"
+       + "            - Add the contents of file.jar to a gcj map database\n"
+       + "    gcj-dbtool -f file.gcjdb file.jar file.so\n"
+       + "            - Add the contents of file.jar to a gcj map database\n"
+       + "    gcj-dbtool -t file.gcjdb            - Test a gcj map database\n"
+       + "    gcj-dbtool -l file.gcjdb            - List a gcj map database\n"
+       + "    gcj-dbtool [-][-0] -m dest.gcjdb [source.gcjdb]...\n"
+       + "            - Merge gcj map databases into dest\n"
+       + "              Replaces dest\n"
+       + "              To add to dest, include dest in the list of sources\n"
+       + "              If the first arg is -, read the list from stdin\n"
+       + "              If the first arg is -0, filenames separated by nul\n"
+       + "    gcj-dbtool -p [LIBDIR]              - Print default database name"
+       );
+  }
+
+  // Add a jar to a map.  This copies the map first and returns a
+  // different map that contains the data.  The original map is
+  // closed.
+
+  private static PersistentByteMap 
+  addJar(File f, PersistentByteMap b, File soFile)
+    throws Exception
+  {
+    MessageDigest md = MessageDigest.getInstance("MD5");
+
+    JarFile jar = new JarFile (f);
+
+    int count = 0;
+    {
+      Enumeration entries = jar.entries();      
+      while (entries.hasMoreElements())
+	{
+	  JarEntry classfile = (JarEntry)entries.nextElement();
+	  if (classfile.getName().endsWith(".class"))
+	    count++;
+	}
+    }
+
+    if (verbose)
+      System.err.println("adding " + count + " elements from "
+			 + f + " to " + b.getFile());
+    
+    // Maybe resize the destination map.  We're allowing plenty of
+    // extra space by using a loadFactor of 2.  
+    b = resizeMap(b, (b.size() + count) * 2, true);
+
+    Enumeration entries = jar.entries();
+
+    byte[] soFileName = soFile.getCanonicalPath().getBytes("UTF-8");
+    while (entries.hasMoreElements())
+      {
+	JarEntry classfile = (JarEntry)entries.nextElement();
+	if (classfile.getName().endsWith(".class"))
+	  {
+	    InputStream str = jar.getInputStream(classfile);
+	    int length = (int) classfile.getSize();
+	    if (length == -1)
+	      throw new EOFException();
+
+	    byte[] data = new byte[length];
+	    int pos = 0;
+	    while (length - pos > 0)
+	      {
+		int len = str.read(data, pos, length - pos);
+		if (len == -1)
+		  throw new EOFException("Not enough data reading from: "
+					 + classfile.getName());
+		pos += len;
+	      }
+	    b.put(md.digest(data), soFileName);
+	  }
+      }
+    return b;
+  }    
+
+  // Resize a map by creating a new one with the same data and
+  // renaming it.  If close is true, close the original map.
+
+  static PersistentByteMap resizeMap(PersistentByteMap m, int newCapacity, boolean close)
+    throws IOException, IllegalAccessException
+  {
+    newCapacity = Math.max(m.capacity(), newCapacity);
+    File name = m.getFile();
+    File copy = File.createTempFile(name.getName(), "", name.getParentFile());
+    try
+      {
+	PersistentByteMap dest 
+	  = PersistentByteMap.emptyPersistentByteMap
+	  (copy, newCapacity, newCapacity*32);
+	dest.putAll(m);
+	dest.force();
+	if (close)
+	  m.close();
+	copy.renameTo(name);
+	return dest;
+      }
+    catch (Exception e)
+      {
+	copy.delete();
+      }
+    return null;
+  }
+    
+	 
+  static String bytesToString(byte[] b)
+  {
+    StringBuffer hexBytes = new StringBuffer();
+    int length = b.length;
+    for (int i = 0; i < length; ++i)
+      {
+	int v = b[i] & 0xff;
+	if (v < 16)
+	  hexBytes.append('0');
+	hexBytes.append(Integer.toHexString(v));
+      }
+    return hexBytes.toString();
+  }
+
+
+  // Return a Fileset, either from a String array or from System.in,
+  // depending on fileListFromStdin.
+  private static final Fileset getFiles(String[] s, int startPos,
+					boolean fileListFromStdin,
+					char separator)
+  {
+    if (fileListFromStdin)
+      return new Fileset(System.in, separator);
+    else
+      return new Fileset(s, startPos, s.length);
+  }
+}
+
+// Parse a stream into tokens.  The separator can be any char, and
+// space is equivalent to any whitepace character.
+class Tokenizer
+{
+  final Reader r;
+  final char separator;
+
+  Tokenizer(Reader r, char separator)
+  {
+    this.r = r;
+    this.separator = separator;
+  }
+
+  boolean isSeparator(int c)
+  {
+    if (Character.isWhitespace(separator))
+      return Character.isWhitespace((char)c);
+    else
+      return c == separator;
+  }
+
+  // Parse a token from the input stream.  Return the empty string
+  // when the stream is exhausted.
+  String nextToken ()
+  {
+    StringBuffer buf = new StringBuffer();
+    int c;
+    try
+      {
+	while ((c = r.read()) != -1)
+	  {
+	    if (! isSeparator(c))
+	      {
+		buf.append((char)c);
+		break;
+	      }
+	  }
+	while ((c = r.read()) != -1)
+	  {
+	    if (isSeparator(c))
+	      break;
+	    else
+	      buf.append((char)c);
+	  }
+      }
+    catch (java.io.IOException e)
+      {
+      }
+    return buf.toString();
+  }
+}
+
+// A Fileset is a container for a set of files; it can be created
+// either from a string array or from an input stream, given a
+// separator character.
+class Fileset
+{
+  LinkedHashSet files = new LinkedHashSet();
+  
+  Fileset (String[] s, int start, int end)
+  {
+    for (int i = start; i < end; i++)
+      {
+	files.add(new File(s[i]));
+      }
+  }
+
+  Fileset (InputStream is, char separator)
+  {
+    Reader r = new BufferedReader(new InputStreamReader(is));
+    Tokenizer st = new Tokenizer(r, separator);
+    String name;
+    while (! "".equals(name = st.nextToken()))
+      files.add(new File(name));
+  }
+
+  Iterator iterator()
+  {
+    return files.iterator();
+  }
+
+  int size()
+  {
+    return files.size();
+  }
+}
diff --git a/libjava/gnu/gcj/tools/gcj_dbtool/Tokenizer.h b/libjava/gnu/gcj/tools/gcj_dbtool/Tokenizer.h
new file mode 100644
index 000000000..7c5c411bb
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gcj_dbtool/Tokenizer.h
@@ -0,0 +1,40 @@
+
+// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-
+
+#ifndef __gnu_gcj_tools_gcj_dbtool_Tokenizer__
+#define __gnu_gcj_tools_gcj_dbtool_Tokenizer__
+
+#pragma interface
+
+#include <java/lang/Object.h>
+extern "Java"
+{
+  namespace gnu
+  {
+    namespace gcj
+    {
+      namespace tools
+      {
+        namespace gcj_dbtool
+        {
+            class Tokenizer;
+        }
+      }
+    }
+  }
+}
+
+class gnu::gcj::tools::gcj_dbtool::Tokenizer : public ::java::lang::Object
+{
+
+public: // actually package-private
+  Tokenizer(::java::io::Reader *, jchar);
+  virtual jboolean isSeparator(jint);
+  virtual ::java::lang::String * nextToken();
+  ::java::io::Reader * __attribute__((aligned(__alignof__( ::java::lang::Object)))) r;
+  jchar separator;
+public:
+  static ::java::lang::Class class$;
+};
+
+#endif // __gnu_gcj_tools_gcj_dbtool_Tokenizer__
diff --git a/libjava/gnu/gcj/tools/gcj_dbtool/natMain.cc b/libjava/gnu/gcj/tools/gcj_dbtool/natMain.cc
new file mode 100644
index 000000000..52ba0d7d1
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gcj_dbtool/natMain.cc
@@ -0,0 +1,24 @@
+// natMain -- gcj-dbtool native code.
+
+/* Copyright (C) 2005  Free Software Foundation
+
+   This file is part of gcj-dbtool.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+/* Author: Anthony Green <green@redhat.com>.  */
+
+#include <config.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+
+#include <gnu/gcj/tools/gcj_dbtool/Main.h>
+
+java::lang::String *
+gnu::gcj::tools::gcj_dbtool::Main::getDbPathTail ()
+{
+  return JvNewStringLatin1 (LIBGCJ_DEFAULT_DATABASE_PATH_TAIL);
+}
-- 
cgit v1.2.3