OSDN Git Service

gcc/java:
authordaney <daney@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 15 Feb 2007 17:25:24 +0000 (17:25 +0000)
committerdaney <daney@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 15 Feb 2007 17:25:24 +0000 (17:25 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@122007 138bc75d-0d04-0410-961f-82ee72b054a4

51 files changed:
gcc/java/ChangeLog
gcc/java/Make-lang.in
gcc/java/gcj.texi
libjava/ChangeLog
libjava/Makefile.am
libjava/Makefile.in
libjava/classpath/ChangeLog.gcj
libjava/classpath/lib/gnu/gcj/util/GCInfo.class [new file with mode: 0644]
libjava/classpath/lib/gnu/gcj/util/UtilPermission.class [new file with mode: 0644]
libjava/classpath/tools/Makefile.am
libjava/classpath/tools/Makefile.in
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap$PtrMarks.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap$SizeKind.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BytePtr.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ItemList.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$1$Info.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$1.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$2.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$3.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$4.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$OptionParser.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$SubstringComparator.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap$Range.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap$RangeComparator.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ObjectMap$ObjectItem.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ObjectMap.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/SymbolLookup.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/SymbolTable.class [new file with mode: 0644]
libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ToolPrefix.class [new file with mode: 0644]
libjava/configure
libjava/configure.ac
libjava/gnu/gcj/tools/gc_analyze/BlockMap.java [new file with mode: 0644]
libjava/gnu/gcj/tools/gc_analyze/BytePtr.java [new file with mode: 0644]
libjava/gnu/gcj/tools/gc_analyze/ItemList.java [new file with mode: 0644]
libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java [new file with mode: 0644]
libjava/gnu/gcj/tools/gc_analyze/MemoryMap.java [new file with mode: 0644]
libjava/gnu/gcj/tools/gc_analyze/ObjectMap.java [new file with mode: 0644]
libjava/gnu/gcj/tools/gc_analyze/SymbolLookup.java [new file with mode: 0644]
libjava/gnu/gcj/tools/gc_analyze/SymbolTable.java [new file with mode: 0644]
libjava/gnu/gcj/tools/gc_analyze/ToolPrefix.java [new file with mode: 0644]
libjava/gnu/gcj/util/GCInfo.h [new file with mode: 0644]
libjava/gnu/gcj/util/GCInfo.java [new file with mode: 0644]
libjava/gnu/gcj/util/UtilPermission.h [new file with mode: 0644]
libjava/gnu/gcj/util/UtilPermission.java [new file with mode: 0644]
libjava/gnu/gcj/util/natGCInfo.cc [new file with mode: 0644]
libjava/include/config.h.in
libjava/scripts/makemake.tcl
libjava/sources.am

index 03c4f96..f9ef73f 100644 (file)
@@ -1,3 +1,12 @@
+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.
+
 2007-02-07  Andrew Haley  <aph@redhat.com>
 
        * class.c (uncache_this_class_ref): New.
index f1c347f..a202494 100644 (file)
@@ -139,7 +139,7 @@ java.pdf: doc/gcj.pdf
 java.html: $(build_htmldir)/java/index.html
 JAVA_MANFILES = doc/gcj.1 doc/jcf-dump.1 doc/gij.1 \
                 doc/jv-convert.1 doc/grmic.1 doc/grmiregistry.1 \
-               doc/gcj-dbtool.1
+               doc/gcj-dbtool.1 doc/gc-analyze.1
 
 java.man: $(JAVA_MANFILES)
 
@@ -208,6 +208,7 @@ java.maintainer-clean:
        -rm -f $(docobjdir)/grmic.1
        -rm -f $(docobjdir)/grmiregistry.1
        -rm -f $(docobjdir)/gcj-dbtool.1
+       -rm -f $(docobjdir)/gc-analyze.1
 #\f
 # Stage hooks:
 # The main makefile has already created stage?/java.
@@ -318,7 +319,7 @@ $(build_htmldir)/java/index.html: $(TEXI_JAVA_FILES)
        $(TEXI2HTML) -I $(gcc_docdir)/include -I $(srcdir)/java -o $(@D) $<
 
 .INTERMEDIATE: gcj.pod jcf-dump.pod gij.pod \
-  jv-convert.pod grmic.pod grmiregistry.pod gcj-dbtool.pod
+  jv-convert.pod grmic.pod grmiregistry.pod gcj-dbtool.pod gc-analyze.pod
 
 gcj.pod: java/gcj.texi
        -$(TEXI2POD) -D gcj < $< > $@
@@ -334,15 +335,17 @@ grmiregistry.pod: java/gcj.texi
        -$(TEXI2POD) -D grmiregistry < $< > $@
 gcj-dbtool.pod: java/gcj.texi
        -$(TEXI2POD) -D gcj-dbtool < $< > $@
+gc-analyze.pod: java/gcj.texi
+       -$(TEXI2POD) -D gc-analyze < $< > $@
 
 # Install the man pages.
 java.install-man: installdirs \
                   $(DESTDIR)$(man1dir)/$(JAVA_INSTALL_NAME)$(man1ext) \
                  $(JAVA_TARGET_INDEPENDENT_BIN_TOOLS:%=doc/%.1) \
                  doc/gij.1 doc/jv-convert.1 doc/grmic.1 doc/grmiregistry.1 \
-                 doc/gcj-dbtool.1
+                 doc/gcj-dbtool.1 doc/gc-analyze.1
        for tool in $(JAVA_TARGET_INDEPENDENT_BIN_TOOLS) \
-               gij jv-convert grmic grmiregistry gcj-dbtool ; do \
+               gij jv-convert grmic grmiregistry gcj-dbtool gc-analyze ; do \
          tool_transformed_name=`echo $$tool|sed '$(program_transform_name)'`; \
          man_name=$(DESTDIR)$(man1dir)/$${tool_transformed_name}$(man1ext); \
          rm -f $$man_name ; \
index aa86ba4..8bd9d5b 100644 (file)
@@ -17,7 +17,7 @@
 @c the word ``Java'.
 
 @c When this manual is copyrighted.
-@set copyrights-gcj 2001, 2002, 2003, 2004, 2005
+@set copyrights-gcj 2001, 2002, 2003, 2004, 2005, 2006, 2007
 
 @c Versions
 @set which-gcj GCC-@value{version-GCC}
@@ -79,6 +79,8 @@ man page gfdl(7).
                             Generate stubs for Remote Method Invocation.
 * grmiregistry: (gcj)Invoking grmiregistry.
                             The remote object registry.
+* gc-analyze: (gcj)Invoking gc-analyze.
+                            Analyze Garbage Collector (GC) memory dumps.
 @end direntry
 @end format
 
@@ -125,6 +127,7 @@ files and object files, and it can read both Java source code and
 * Invoking jv-convert:: Converting from one encoding to another
 * Invoking grmic::      Generate stubs for Remote Method Invocation.
 * Invoking grmiregistry:: The remote object registry.
+* Invoking gc-analyze:: Analyze Garbage Collector (GC) memory dumps.
 * About CNI::           Description of the Compiled Native Interface
 * System properties::   Modifying runtime behavior of the libgcj library
 * Resources::          Where to look for more information
@@ -1412,6 +1415,89 @@ Print version information, then exit.
 @c man end
 
 
+@node Invoking gc-analyze
+@chapter Invoking gc-analyze
+
+@c man title gc-analyze Analyze Garbage Collector (GC) memory dumps
+
+@c man begin SYNOPSIS gc-analyze
+@command{gc-analyze} [@option{OPTION}] @dots{} [@var{file}]
+@ignore
+  [@option{-v}]
+  [@option{--verbose}]
+  [@option{-p} @var{tool-prefix}]
+  [@option{-d} @var{directory}]
+  [@option{--version}]
+  [@option{--help}]
+@end ignore
+@c man end
+
+@c man begin DESCRIPTION gc-analyze
+
+@command{gc-analyze} prints an analysis of a GC memory dump to
+standard out.
+
+The memory dumps may be created by calling
+@code{gnu.gcj.util.GCInfo.enumerate(String namePrefix)} from java
+code.  A memory dump will be created on an out of memory condition if
+@code{gnu.gcj.util.GCInfo.setOOMDump(String namePrefix)} is called
+before the out of memory occurs.
+
+Running this program will create two files: @file{TestDump001} and
+@file{TestDump001.bytes}.
+
+@example
+import gnu.gcj.util.*;
+import java.util.*;
+
+public class GCDumpTest
+@{
+    static public void main(String args[])
+    @{
+        ArrayList<String> l = new ArrayList<String>(1000);
+        
+        for (int i = 1; i < 1500; i++) @{
+            l.add("This is string #" + i);
+        @}
+        GCInfo.enumerate("TestDump");
+    @}
+@}
+@end example
+
+The memory dump may then be displayed by running:
+
+@example
+gc-analyze -v TestDump001
+@end example
+
+@c FIXME: Add real information here.
+@c This really isn't much more than the --help output.
+
+@c man end
+
+@c man begin OPTIONS gc-analyze
+
+@table @gcctabopt
+@item --verbose
+@itemx -v
+Verbose output.
+
+@item -p @var{tool-prefix}
+Prefix added to the names of the @command{nm} and @command{readelf} commands.
+
+@item -d @var{directory}
+Directory that contains the executable and shared libraries used when
+the dump was generated.
+
+@item --help
+Print a help message, then exit.
+
+@item --version
+Print version information, then exit.
+@end table
+
+@c man end
+
 @node About CNI
 @chapter About CNI
 
index 6eeacf0..9d4406f 100644 (file)
@@ -1,3 +1,59 @@
+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.
+
 2007-02-15  David Daney  <ddaney@avtrex.com>
 
        * gnu/java/net/PlainSocketImpl.h: Regenerate.
index 9841f60..7c700e1 100644 (file)
@@ -73,7 +73,7 @@ db_pathtail = gcj-$(gcc_version)/$(db_name)
 if NATIVE
 bin_PROGRAMS = jv-convert gij grmic grmiregistry gcj-dbtool \
        gappletviewer gjarsigner gkeytool gjar gjavah gnative2ascii \
-       gorbd grmid gserialver gtnameserv
+       gorbd grmid gserialver gtnameserv gc-analyze
 
 ## It is convenient to actually build and install the default database
 ## when gcj-dbtool is available.
@@ -647,6 +647,20 @@ gcj_dbtool_LDADD = gnu/gcj/tools/gcj_dbtool.lo -L$(here)/.libs libgcj.la
 ## linking this program.
 gcj_dbtool_DEPENDENCIES = gnu/gcj/tools/gcj_dbtool.lo libgcj.la libgcj.spec
 
+gc_analyze_SOURCES =
+
+## We need -nodefaultlibs because we want to avoid gcj's `-lgcj'.  We
+## need this because we are explicitly using libtool to link using the
+## `.la' file.
+gc_analyze_LDFLAGS = --main=gnu.gcj.tools.gc_analyze.MemoryAnalyze \
+        -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS)
+gc_analyze_LINK = $(GCJLINK)
+## See jv_convert_LDADD.
+gc_analyze_LDADD = -L$(here)/.libs libgcj-tools.la libgcj.la
+## Depend on the spec file to make sure it is up to date before
+## linking this program.
+gc_analyze_DEPENDENCIES = libgcj-tools.la libgcj.la libgcj.spec
+
 gij_SOURCES = 
 ## We need -nodefaultlibs because we want to avoid gcj's `-lgcj'.  We
 ## need this because we are explicitly using libtool to link using the
@@ -831,6 +845,7 @@ gnu/gcj/runtime/natSharedLibLoader.cc \
 gnu/gcj/runtime/natSystemClassLoader.cc \
 gnu/gcj/runtime/natStringBuffer.cc \
 gnu/gcj/util/natDebug.cc \
+gnu/gcj/util/natGCInfo.cc \
 gnu/java/lang/natMainThread.cc \
 gnu/java/lang/management/natVMClassLoadingMXBeanImpl.cc \
 gnu/java/lang/management/natVMCompilationMXBeanImpl.cc \
index 5411f07..b7cfb00 100644 (file)
@@ -51,7 +51,7 @@ target_triplet = @target@
 @NATIVE_TRUE@  gjar$(EXEEXT) gjavah$(EXEEXT) \
 @NATIVE_TRUE@  gnative2ascii$(EXEEXT) gorbd$(EXEEXT) \
 @NATIVE_TRUE@  grmid$(EXEEXT) gserialver$(EXEEXT) \
-@NATIVE_TRUE@  gtnameserv$(EXEEXT)
+@NATIVE_TRUE@  gtnameserv$(EXEEXT) gc-analyze$(EXEEXT)
 @BUILD_ECJ1_TRUE@libexecsub_PROGRAMS = ecjx$(EXEEXT)
 @ANONVERSCRIPT_TRUE@am__append_5 = -Wl,--version-script=$(srcdir)/libgcj.ver
 @USING_GCC_TRUE@am__append_6 = $(WARNINGS)
@@ -305,7 +305,7 @@ am__libgcj_la_SOURCES_DIST = prims.cc jni.cc jvmti.cc exception.cc \
        gnu/gcj/runtime/natSharedLibLoader.cc \
        gnu/gcj/runtime/natSystemClassLoader.cc \
        gnu/gcj/runtime/natStringBuffer.cc gnu/gcj/util/natDebug.cc \
-       gnu/java/lang/natMainThread.cc \
+       gnu/gcj/util/natGCInfo.cc gnu/java/lang/natMainThread.cc \
        gnu/java/lang/management/natVMClassLoadingMXBeanImpl.cc \
        gnu/java/lang/management/natVMCompilationMXBeanImpl.cc \
        gnu/java/lang/management/natVMGarbageCollectorMXBeanImpl.cc \
@@ -368,7 +368,7 @@ am__objects_2 = gnu/classpath/jdwp/natVMFrame.lo \
        gnu/gcj/runtime/natSharedLibLoader.lo \
        gnu/gcj/runtime/natSystemClassLoader.lo \
        gnu/gcj/runtime/natStringBuffer.lo gnu/gcj/util/natDebug.lo \
-       gnu/java/lang/natMainThread.lo \
+       gnu/gcj/util/natGCInfo.lo gnu/java/lang/natMainThread.lo \
        gnu/java/lang/management/natVMClassLoadingMXBeanImpl.lo \
        gnu/java/lang/management/natVMCompilationMXBeanImpl.lo \
        gnu/java/lang/management/natVMGarbageCollectorMXBeanImpl.lo \
@@ -438,6 +438,8 @@ am_ecjx_OBJECTS =
 ecjx_OBJECTS = $(am_ecjx_OBJECTS)
 am_gappletviewer_OBJECTS =
 gappletviewer_OBJECTS = $(am_gappletviewer_OBJECTS)
+am_gc_analyze_OBJECTS =
+gc_analyze_OBJECTS = $(am_gc_analyze_OBJECTS)
 am_gcj_dbtool_OBJECTS = gnu/gcj/tools/gcj_dbtool/natMain.$(OBJEXT)
 gcj_dbtool_OBJECTS = $(am_gcj_dbtool_OBJECTS)
 am__gen_from_JIS_SOURCES_DIST = gnu/gcj/convert/gen-from-JIS.c \
@@ -501,23 +503,23 @@ SOURCES = $(lib_gnu_awt_xlib_la_SOURCES) $(libgcj_tools_la_SOURCES) \
        $(libgcj_la_SOURCES) $(EXTRA_libgcj_la_SOURCES) \
        $(libgcj_bc_la_SOURCES) $(libgij_la_SOURCES) \
        $(libjvm_la_SOURCES) $(ecjx_SOURCES) $(gappletviewer_SOURCES) \
-       $(gcj_dbtool_SOURCES) $(gen_from_JIS_SOURCES) $(gij_SOURCES) \
-       $(gjar_SOURCES) $(gjarsigner_SOURCES) $(gjavah_SOURCES) \
-       $(gkeytool_SOURCES) $(gnative2ascii_SOURCES) $(gorbd_SOURCES) \
-       $(grmic_SOURCES) $(grmid_SOURCES) $(grmiregistry_SOURCES) \
-       $(gserialver_SOURCES) $(gtnameserv_SOURCES) \
-       $(jv_convert_SOURCES)
+       $(gc_analyze_SOURCES) $(gcj_dbtool_SOURCES) \
+       $(gen_from_JIS_SOURCES) $(gij_SOURCES) $(gjar_SOURCES) \
+       $(gjarsigner_SOURCES) $(gjavah_SOURCES) $(gkeytool_SOURCES) \
+       $(gnative2ascii_SOURCES) $(gorbd_SOURCES) $(grmic_SOURCES) \
+       $(grmid_SOURCES) $(grmiregistry_SOURCES) $(gserialver_SOURCES) \
+       $(gtnameserv_SOURCES) $(jv_convert_SOURCES)
 DIST_SOURCES = $(lib_gnu_awt_xlib_la_SOURCES) \
        $(libgcj_tools_la_SOURCES) $(am__libgcj_la_SOURCES_DIST) \
        $(EXTRA_libgcj_la_SOURCES) $(libgcj_bc_la_SOURCES) \
        $(libgij_la_SOURCES) $(libjvm_la_SOURCES) $(ecjx_SOURCES) \
-       $(gappletviewer_SOURCES) $(gcj_dbtool_SOURCES) \
-       $(am__gen_from_JIS_SOURCES_DIST) $(gij_SOURCES) \
-       $(gjar_SOURCES) $(gjarsigner_SOURCES) $(gjavah_SOURCES) \
-       $(gkeytool_SOURCES) $(gnative2ascii_SOURCES) $(gorbd_SOURCES) \
-       $(grmic_SOURCES) $(grmid_SOURCES) $(grmiregistry_SOURCES) \
-       $(gserialver_SOURCES) $(gtnameserv_SOURCES) \
-       $(jv_convert_SOURCES)
+       $(gappletviewer_SOURCES) $(gc_analyze_SOURCES) \
+       $(gcj_dbtool_SOURCES) $(am__gen_from_JIS_SOURCES_DIST) \
+       $(gij_SOURCES) $(gjar_SOURCES) $(gjarsigner_SOURCES) \
+       $(gjavah_SOURCES) $(gkeytool_SOURCES) $(gnative2ascii_SOURCES) \
+       $(gorbd_SOURCES) $(grmic_SOURCES) $(grmid_SOURCES) \
+       $(grmiregistry_SOURCES) $(gserialver_SOURCES) \
+       $(gtnameserv_SOURCES) $(jv_convert_SOURCES)
 RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
        html-recursive info-recursive install-data-recursive \
        install-exec-recursive install-info-recursive \
@@ -1344,7 +1346,9 @@ gnu/gcj/tools/gcj_dbtool/Main.java
 
 gnu_gcj_tools_gcj_dbtool_header_files = $(patsubst %.java,%.h,$(gnu_gcj_tools_gcj_dbtool_source_files))
 gnu_gcj_util_source_files = \
-gnu/gcj/util/Debug.java
+gnu/gcj/util/Debug.java \
+gnu/gcj/util/GCInfo.java \
+gnu/gcj/util/UtilPermission.java
 
 gnu_gcj_util_header_files = $(patsubst %.java,%.h,$(gnu_gcj_util_source_files))
 gnu_gcj_xlib_source_files = \
@@ -7818,6 +7822,13 @@ gcj_dbtool_LDFLAGS = --main=gnu.gcj.tools.gcj_dbtool.Main \
 gcj_dbtool_LINK = $(GCJLINK)
 gcj_dbtool_LDADD = gnu/gcj/tools/gcj_dbtool.lo -L$(here)/.libs libgcj.la
 gcj_dbtool_DEPENDENCIES = gnu/gcj/tools/gcj_dbtool.lo libgcj.la libgcj.spec
+gc_analyze_SOURCES = 
+gc_analyze_LDFLAGS = --main=gnu.gcj.tools.gc_analyze.MemoryAnalyze \
+        -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS)
+
+gc_analyze_LINK = $(GCJLINK)
+gc_analyze_LDADD = -L$(here)/.libs libgcj-tools.la libgcj.la
+gc_analyze_DEPENDENCIES = libgcj-tools.la libgcj.la libgcj.spec
 gij_SOURCES = 
 gij_LDFLAGS = -rpath $(libdir)/gcj-$(gcc_version) -rpath $(toolexeclibdir) \
        -shared-libgcc $(THREADLDFLAGS)
@@ -7947,6 +7958,7 @@ gnu/gcj/runtime/natSharedLibLoader.cc \
 gnu/gcj/runtime/natSystemClassLoader.cc \
 gnu/gcj/runtime/natStringBuffer.cc \
 gnu/gcj/util/natDebug.cc \
+gnu/gcj/util/natGCInfo.cc \
 gnu/java/lang/natMainThread.cc \
 gnu/java/lang/management/natVMClassLoadingMXBeanImpl.cc \
 gnu/java/lang/management/natVMCompilationMXBeanImpl.cc \
@@ -8360,6 +8372,8 @@ gnu/gcj/util/$(DEPDIR)/$(am__dirstamp):
        @: > gnu/gcj/util/$(DEPDIR)/$(am__dirstamp)
 gnu/gcj/util/natDebug.lo: gnu/gcj/util/$(am__dirstamp) \
        gnu/gcj/util/$(DEPDIR)/$(am__dirstamp)
+gnu/gcj/util/natGCInfo.lo: gnu/gcj/util/$(am__dirstamp) \
+       gnu/gcj/util/$(DEPDIR)/$(am__dirstamp)
 gnu/java/lang/$(am__dirstamp):
        @$(mkdir_p) gnu/java/lang
        @: > gnu/java/lang/$(am__dirstamp)
@@ -8694,6 +8708,9 @@ ecjx$(EXEEXT): $(ecjx_OBJECTS) $(ecjx_DEPENDENCIES)
 gappletviewer$(EXEEXT): $(gappletviewer_OBJECTS) $(gappletviewer_DEPENDENCIES) 
        @rm -f gappletviewer$(EXEEXT)
        $(gappletviewer_LINK) $(gappletviewer_LDFLAGS) $(gappletviewer_OBJECTS) $(gappletviewer_LDADD) $(LIBS)
+gc-analyze$(EXEEXT): $(gc_analyze_OBJECTS) $(gc_analyze_DEPENDENCIES) 
+       @rm -f gc-analyze$(EXEEXT)
+       $(gc_analyze_LINK) $(gc_analyze_LDFLAGS) $(gc_analyze_OBJECTS) $(gc_analyze_LDADD) $(LIBS)
 gnu/gcj/tools/gcj_dbtool/$(am__dirstamp):
        @$(mkdir_p) gnu/gcj/tools/gcj_dbtool
        @: > gnu/gcj/tools/gcj_dbtool/$(am__dirstamp)
@@ -8826,6 +8843,8 @@ mostlyclean-compile:
        -rm -f gnu/gcj/tools/gcj_dbtool/natMain.$(OBJEXT)
        -rm -f gnu/gcj/util/natDebug.$(OBJEXT)
        -rm -f gnu/gcj/util/natDebug.lo
+       -rm -f gnu/gcj/util/natGCInfo.$(OBJEXT)
+       -rm -f gnu/gcj/util/natGCInfo.lo
        -rm -f gnu/gcj/xlib/lib_gnu_awt_xlib_la-natClip.$(OBJEXT)
        -rm -f gnu/gcj/xlib/lib_gnu_awt_xlib_la-natClip.lo
        -rm -f gnu/gcj/xlib/lib_gnu_awt_xlib_la-natColormap.$(OBJEXT)
@@ -9035,6 +9054,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natSystemClassLoader.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gcj_dbtool/$(DEPDIR)/natMain.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/util/$(DEPDIR)/natDebug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/util/$(DEPDIR)/natGCInfo.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/xlib/$(DEPDIR)/lib_gnu_awt_xlib_la-natClip.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/xlib/$(DEPDIR)/lib_gnu_awt_xlib_la-natColormap.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/xlib/$(DEPDIR)/lib_gnu_awt_xlib_la-natDisplay.Plo@am__quote@
index e4a71a8..c147ab6 100644 (file)
@@ -1,3 +1,8 @@
+2007-02-15  David Daney  <ddaney@avtrex.com>
+
+       * tools/Makefile.am (TOOLS_ZIP): Add classes from vm-tools-packages.
+       * tools/Makefile.in: Regenerated.
+
 2007-02-15  Gary Benson  <gbenson@redhat.com>
 
        * javax/management/AttributeList.java: Updated.
diff --git a/libjava/classpath/lib/gnu/gcj/util/GCInfo.class b/libjava/classpath/lib/gnu/gcj/util/GCInfo.class
new file mode 100644 (file)
index 0000000..e07bb93
Binary files /dev/null and b/libjava/classpath/lib/gnu/gcj/util/GCInfo.class differ
diff --git a/libjava/classpath/lib/gnu/gcj/util/UtilPermission.class b/libjava/classpath/lib/gnu/gcj/util/UtilPermission.class
new file mode 100644 (file)
index 0000000..f7d9dad
Binary files /dev/null and b/libjava/classpath/lib/gnu/gcj/util/UtilPermission.class differ
index f47191c..8ba984b 100755 (executable)
@@ -155,12 +155,19 @@ $(TOOLS_ZIP): $(TOOLS_JAVA_FILES)
 ##     mkdir classes asm
        find $(srcdir)/external/asm -name '*.java' -print > asm.lst
        find $(srcdir)/gnu/classpath/tools -name '*.java' -print > classes.lst
-       cat classes.lst asm.lst > all-classes.lst
+       if [ -f $(top_builddir)/../vm-tools-packages ]; then \
+           for pkg in `cat $(top_builddir)/../vm-tools-packages`; do \
+             $(FIND) $(top_srcdir)/../$$pkg -follow -name '*.java' -print >> vm-tools.lst; \
+           done \
+       else \
+           echo -n > vm-tools.lst; \
+       fi
+       cat classes.lst asm.lst vm-tools.lst > all-classes.lst
 if JAVA_MAINTAINER_MODE
 ## Compile ASM separately as it is latin-1 encoded.
        AC=`echo $(JCOMPILER) | sed -e 's/UTF-8/ISO-8859-1/g'`; \
          $$AC -g -w -d $(srcdir)/asm @asm.lst
-       $(JCOMPILER) -g -w -d $(srcdir)/classes @classes.lst
+       $(JCOMPILER) -g -w -d $(srcdir)/classes @classes.lst @vm-tools.lst
 ## Copy over tools resource files.
        @list=`cd $(top_srcdir)/resource && find gnu/classpath/tools -name \*.properties -print`; \
        for p in $$list; do \
index cb0525f..960dc6e 100644 (file)
@@ -1079,10 +1079,17 @@ dist-hook:
 $(TOOLS_ZIP): $(TOOLS_JAVA_FILES)
        find $(srcdir)/external/asm -name '*.java' -print > asm.lst
        find $(srcdir)/gnu/classpath/tools -name '*.java' -print > classes.lst
-       cat classes.lst asm.lst > all-classes.lst
+       if [ -f $(top_builddir)/../vm-tools-packages ]; then \
+           for pkg in `cat $(top_builddir)/../vm-tools-packages`; do \
+             $(FIND) $(top_srcdir)/../$$pkg -follow -name '*.java' -print >> vm-tools.lst; \
+           done \
+       else \
+           echo -n > vm-tools.lst; \
+       fi
+       cat classes.lst asm.lst vm-tools.lst > all-classes.lst
 @JAVA_MAINTAINER_MODE_TRUE@    AC=`echo $(JCOMPILER) | sed -e 's/UTF-8/ISO-8859-1/g'`; \
 @JAVA_MAINTAINER_MODE_TRUE@      $$AC -g -w -d $(srcdir)/asm @asm.lst
-@JAVA_MAINTAINER_MODE_TRUE@    $(JCOMPILER) -g -w -d $(srcdir)/classes @classes.lst
+@JAVA_MAINTAINER_MODE_TRUE@    $(JCOMPILER) -g -w -d $(srcdir)/classes @classes.lst @vm-tools.lst
 @JAVA_MAINTAINER_MODE_TRUE@    @list=`cd $(top_srcdir)/resource && find gnu/classpath/tools -name \*.properties -print`; \
 @JAVA_MAINTAINER_MODE_TRUE@    for p in $$list; do \
 @JAVA_MAINTAINER_MODE_TRUE@      dirname=classes/`dirname $$p`; \
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap$PtrMarks.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap$PtrMarks.class
new file mode 100644 (file)
index 0000000..59094b9
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap$PtrMarks.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap$SizeKind.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap$SizeKind.class
new file mode 100644 (file)
index 0000000..4a9c99a
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap$SizeKind.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap.class
new file mode 100644 (file)
index 0000000..b29214c
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BlockMap.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BytePtr.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BytePtr.class
new file mode 100644 (file)
index 0000000..c5a812e
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/BytePtr.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ItemList.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ItemList.class
new file mode 100644 (file)
index 0000000..c1098e5
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ItemList.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$1$Info.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$1$Info.class
new file mode 100644 (file)
index 0000000..687e94d
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$1$Info.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$1.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$1.class
new file mode 100644 (file)
index 0000000..9fbf1a5
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$1.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$2.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$2.class
new file mode 100644 (file)
index 0000000..5fa44be
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$2.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$3.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$3.class
new file mode 100644 (file)
index 0000000..2c91530
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$3.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$4.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$4.class
new file mode 100644 (file)
index 0000000..125ac72
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$4.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$OptionParser.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$OptionParser.class
new file mode 100644 (file)
index 0000000..9a12fb8
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$OptionParser.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$SubstringComparator.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$SubstringComparator.class
new file mode 100644 (file)
index 0000000..238c258
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze$SubstringComparator.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze.class
new file mode 100644 (file)
index 0000000..ce5c998
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryAnalyze.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap$Range.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap$Range.class
new file mode 100644 (file)
index 0000000..72d9ee0
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap$Range.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap$RangeComparator.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap$RangeComparator.class
new file mode 100644 (file)
index 0000000..4355000
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap$RangeComparator.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap.class
new file mode 100644 (file)
index 0000000..2646141
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/MemoryMap.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ObjectMap$ObjectItem.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ObjectMap$ObjectItem.class
new file mode 100644 (file)
index 0000000..4a27d3f
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ObjectMap$ObjectItem.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ObjectMap.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ObjectMap.class
new file mode 100644 (file)
index 0000000..f7fc0df
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ObjectMap.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/SymbolLookup.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/SymbolLookup.class
new file mode 100644 (file)
index 0000000..7099959
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/SymbolLookup.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/SymbolTable.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/SymbolTable.class
new file mode 100644 (file)
index 0000000..49e0bbb
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/SymbolTable.class differ
diff --git a/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ToolPrefix.class b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ToolPrefix.class
new file mode 100644 (file)
index 0000000..2224a23
Binary files /dev/null and b/libjava/classpath/tools/classes/gnu/gcj/tools/gc_analyze/ToolPrefix.class differ
index da281d1..04449d5 100755 (executable)
@@ -5087,6 +5087,12 @@ if test "$use_x_awt" != yes; then
    echo gnu/java/awt/peer/x >> standard.omit
 fi
 
+# Tools that need to be compiled against classpath's tools classes
+for package in gnu/gcj/tools/gc_analyze ; do
+    echo $package >> standard.omit
+    echo $package >> vm-tools-packages
+done
+
 if test -z "${with_multisubdir}"; then
    builddotdot=.
 else
@@ -6024,7 +6030,7 @@ test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic"
 case $host in
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 6027 "configure"' > conftest.$ac_ext
+  echo '#line 6033 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -7066,7 +7072,7 @@ if test "${enable_sjlj_exceptions+set}" = set; then
   :
 else
   cat > conftest.$ac_ext << EOF
-#line 7069 "configure"
+#line 7075 "configure"
 struct S { ~S(); };
 void bar();
 void foo()
@@ -7819,7 +7825,7 @@ ac_x_header_dirs='
 /usr/openwin/share/include'
 
 if test "$ac_x_includes" = no; then
-  # Guess where to find include files, by looking for Intrinsic.h.
+  # Guess where to find include files, by looking for Xlib.h.
   # First, try using that file with no special directory specified.
   cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
@@ -7827,7 +7833,7 @@ _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-#include <X11/Intrinsic.h>
+#include <X11/Xlib.h>
 _ACEOF
 if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
   (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
@@ -7854,7 +7860,7 @@ else
 sed 's/^/| /' conftest.$ac_ext >&5
 
   for ac_dir in $ac_x_header_dirs; do
-  if test -r "$ac_dir/X11/Intrinsic.h"; then
+  if test -r "$ac_dir/X11/Xlib.h"; then
     ac_x_includes=$ac_dir
     break
   fi
@@ -7868,7 +7874,7 @@ if test "$ac_x_libraries" = no; then
   # See if we find them without any special options.
   # Don't add to $LIBS permanently.
   ac_save_LIBS=$LIBS
-  LIBS="-lXt $LIBS"
+  LIBS="-lX11 $LIBS"
   if test x$gcc_no_link = xyes; then
   { { echo "$as_me:$LINENO: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&5
 echo "$as_me: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&2;}
@@ -7880,11 +7886,11 @@ _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-#include <X11/Intrinsic.h>
+#include <X11/Xlib.h>
 int
 main ()
 {
-XtMalloc (0)
+XrmInitialize ()
   ;
   return 0;
 }
@@ -10397,6 +10403,37 @@ _ACEOF
 
 fi
 
+     echo "$as_me:$LINENO: checking for /proc/self/maps" >&5
+echo $ECHO_N "checking for /proc/self/maps... $ECHO_C" >&6
+if test "${ac_cv_file__proc_self_maps+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  test "$cross_compiling" = yes &&
+  { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r "/proc/self/maps"; then
+  ac_cv_file__proc_self_maps=yes
+else
+  ac_cv_file__proc_self_maps=no
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_file__proc_self_maps" >&5
+echo "${ECHO_T}$ac_cv_file__proc_self_maps" >&6
+if test $ac_cv_file__proc_self_maps = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE__PROC_SELF_MAPS 1
+_ACEOF
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PROC_SELF_MAPS 1
+_ACEOF
+
+fi
+
    else
      case $host in
      *-linux*)
@@ -10405,6 +10442,11 @@ cat >>confdefs.h <<\_ACEOF
 #define HAVE_PROC_SELF_EXE 1
 _ACEOF
 
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PROC_SELF_MAPS 1
+_ACEOF
+
        ;;
      esac
    fi
@@ -16815,7 +16857,7 @@ if test "${have_tls+set}" = set; then
 else
 
     if test "$cross_compiling" = yes; then
-  if test x$gcc_no_link = xyes; then
+                if test x$gcc_no_link = xyes; then
   { { echo "$as_me:$LINENO: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&5
 echo "$as_me: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&2;}
    { (exit 1); exit 1; }; }
@@ -16855,6 +16897,7 @@ fi
 rm -f conftest.err conftest.$ac_objext \
       conftest$ac_exeext conftest.$ac_ext
 
+
 else
   cat >conftest.$ac_ext <<_ACEOF
 __thread int a; int b; int main() { return a = b; }
@@ -16870,7 +16913,7 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-                      save_LDFLAGS="$LDFLAGS"
+                      chktls_save_LDFLAGS="$LDFLAGS"
       LDFLAGS="-static $LDFLAGS"
       if test x$gcc_no_link = xyes; then
   { { echo "$as_me:$LINENO: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&5
@@ -16942,7 +16985,134 @@ have_tls=yes
 fi
 rm -f conftest.err conftest.$ac_objext \
       conftest$ac_exeext conftest.$ac_ext
-      LDFLAGS="$save_LDFLAGS"
+      LDFLAGS="$chktls_save_LDFLAGS"
+      if test $have_tls = yes; then
+                                               chktls_save_CFLAGS="$CFLAGS"
+       thread_CFLAGS=failed
+       for flag in '' '-pthread' '-lpthread'; do
+         CFLAGS="$flag $chktls_save_CFLAGS"
+         if test x$gcc_no_link = xyes; then
+  { { echo "$as_me:$LINENO: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&5
+echo "$as_me: error: Link tests are not allowed after GCC_NO_EXECUTABLES." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <pthread.h>
+               void *g(void *d) { return NULL; }
+int
+main ()
+{
+pthread_t t; pthread_create(&t,NULL,g,NULL);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  thread_CFLAGS="$flag"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+         if test "X$thread_CFLAGS" != Xfailed; then
+           break
+         fi
+       done
+       CFLAGS="$chktls_save_CFLAGS"
+       if test "X$thread_CFLAGS" != Xfailed; then
+         CFLAGS="$thread_CFLAGS $chktls_save_CFLAGS"
+         if test "$cross_compiling" = yes; then
+  { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run test program while cross compiling
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <pthread.h>
+               __thread int a;
+               static int *a_in_other_thread;
+               static void *
+               thread_func (void *arg)
+               {
+                 a_in_other_thread = &a;
+                 return (void *)0;
+               }
+int
+main ()
+{
+pthread_t thread;
+               void *thread_retval;
+               int *a_in_main_thread;
+               if (pthread_create (&thread, (pthread_attr_t *)0,
+                                   thread_func, (void *)0))
+                 return 0;
+               a_in_main_thread = &a;
+               if (pthread_join (thread, &thread_retval))
+                 return 0;
+               return (a_in_other_thread == a_in_main_thread);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  have_tls=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+have_tls=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+         CFLAGS="$chktls_save_CFLAGS"
+       fi
+      fi
 else
   echo "$as_me: program exited with status $ac_status" >&5
 echo "$as_me: failed program was:" >&5
index 0ee1ee0..a8e536f 100644 (file)
@@ -295,6 +295,12 @@ if test "$use_x_awt" != yes; then
    echo gnu/java/awt/peer/x >> standard.omit
 fi
 
+# Tools that need to be compiled against classpath's tools classes
+for package in gnu/gcj/tools/gc_analyze ; do
+    echo $package >> standard.omit
+    echo $package >> vm-tools-packages
+done
+
 if test -z "${with_multisubdir}"; then
    builddotdot=.
 else
@@ -1012,10 +1018,14 @@ else
    if test x"$cross_compiling" = x"no"; then
      AC_CHECK_FILES(/proc/self/exe, [
        AC_DEFINE(HAVE_PROC_SELF_EXE, 1, [Define if you have /proc/self/exe])])
+     AC_CHECK_FILES(/proc/self/maps, [
+       AC_DEFINE(HAVE_PROC_SELF_MAPS, 1,
+         [Define if you have /proc/self/maps])])
    else
      case $host in
      *-linux*)
        AC_DEFINE(HAVE_PROC_SELF_EXE, 1, [Define if you have /proc/self/exe])
+       AC_DEFINE(HAVE_PROC_SELF_MAPS, 1, [Define if you have /proc/self/maps])
        ;;
      esac
    fi
diff --git a/libjava/gnu/gcj/tools/gc_analyze/BlockMap.java b/libjava/gnu/gcj/tools/gc_analyze/BlockMap.java
new file mode 100644 (file)
index 0000000..6e7adae
--- /dev/null
@@ -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 (file)
index 0000000..4afceee
--- /dev/null
@@ -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 (file)
index 0000000..7912beb
--- /dev/null
@@ -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 (file)
index 0000000..d56a71d
--- /dev/null
@@ -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 (file)
index 0000000..1bc06d5
--- /dev/null
@@ -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 (file)
index 0000000..b55034b
--- /dev/null
@@ -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 (file)
index 0000000..b3963d8
--- /dev/null
@@ -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 (file)
index 0000000..eb5df76
--- /dev/null
@@ -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 (file)
index 0000000..e8d73ae
--- /dev/null
@@ -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 (file)
index 0000000..06e0dd0
--- /dev/null
@@ -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 (file)
index 0000000..73f4718
--- /dev/null
@@ -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 (file)
index 0000000..4c7b226
--- /dev/null
@@ -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 (file)
index 0000000..1ea4cb7
--- /dev/null
@@ -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 (file)
index 0000000..7e5c6fb
--- /dev/null
@@ -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
+
index a4e013d..2c025a2 100644 (file)
 /* Define if you have /proc/self/exe */
 #undef HAVE_PROC_SELF_EXE
 
+/* Define if you have /proc/self/maps */
+#undef HAVE_PROC_SELF_MAPS
+
 /* Define if using POSIX threads that have the mutexattr functions. */
 #undef HAVE_PTHREAD_MUTEXATTR_INIT
 
 /* Define to 1 if you have the file `AC_File'. */
 #undef HAVE__PROC_SELF_EXE
 
+/* Define to 1 if you have the file `AC_File'. */
+#undef HAVE__PROC_SELF_MAPS
+
 /* Define as const if the declaration of iconv() needs const. */
 #undef ICONV_CONST
 
index 78259a3..5a60097 100755 (executable)
@@ -42,6 +42,7 @@ set package_map(.) package
 # These are ignored in Classpath.
 set package_map(gnu/test) ignore
 set package_map(gnu/javax/swing/plaf/gtk) ignore
+set package_map(gnu/gcj/tools/gc_analyze) ignore
 
 set package_map(gnu/java/awt/peer/swing) bc
 
index 0c9953f..79b8832 100644 (file)
@@ -555,7 +555,9 @@ gnu/gcj/tools/gcj_dbtool.list: $(gnu_gcj_tools_gcj_dbtool_source_files)
 
 
 gnu_gcj_util_source_files = \
-gnu/gcj/util/Debug.java
+gnu/gcj/util/Debug.java \
+gnu/gcj/util/GCInfo.java \
+gnu/gcj/util/UtilPermission.java
 
 gnu_gcj_util_header_files = $(patsubst %.java,%.h,$(gnu_gcj_util_source_files))