Index: configure =================================================================== --- configure (revision 113530) +++ configure (working copy) @@ -10229,6 +10229,37 @@ 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*) @@ -10237,6 +10268,11 @@ #define HAVE_PROC_SELF_EXE 1 _ACEOF + +cat >>confdefs.h <<\_ACEOF +#define HAVE_PROC_SELF_MAPS 1 +_ACEOF + ;; esac fi Index: Makefile.in =================================================================== --- Makefile.in (revision 113530) +++ Makefile.in (working copy) @@ -17,7 +17,7 @@ -SOURCES = $(lib_gnu_awt_xlib_la_SOURCES) $(lib_gnu_java_awt_peer_gtk_la_SOURCES) $(lib_gnu_java_awt_peer_qt_la_SOURCES) $(libgcj_la_SOURCES) $(libgcjawt_la_SOURCES) $(libgij_la_SOURCES) $(gcj_dbtool_SOURCES) $(gen_from_JIS_SOURCES) $(gij_SOURCES) $(grmic_SOURCES) $(grmiregistry_SOURCES) $(jv_convert_SOURCES) +SOURCES = $(lib_gnu_awt_xlib_la_SOURCES) $(lib_gnu_java_awt_peer_gtk_la_SOURCES) $(lib_gnu_java_awt_peer_qt_la_SOURCES) $(libgcj_la_SOURCES) $(libgcjawt_la_SOURCES) $(libgij_la_SOURCES) $(gc_analyze_SOURCES) $(gcj_dbtool_SOURCES) $(gen_from_JIS_SOURCES) $(gij_SOURCES) $(grmic_SOURCES) $(grmiregistry_SOURCES) $(jv_convert_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ @@ -48,7 +48,7 @@ @QT_AWT_TRUE@am__append_4 = lib-gnu-java-awt-peer-qt.la @NATIVE_TRUE@bin_PROGRAMS = jv-convert$(EXEEXT) gij$(EXEEXT) \ @NATIVE_TRUE@ grmic$(EXEEXT) grmiregistry$(EXEEXT) \ -@NATIVE_TRUE@ gcj-dbtool$(EXEEXT) +@NATIVE_TRUE@ gcj-dbtool$(EXEEXT) gc_analyze$(EXEEXT) @USING_GCC_TRUE@am__append_5 = $(WARNINGS) @USING_BOEHMGC_TRUE@am__append_6 = boehm.cc @USING_NOGC_TRUE@am__append_7 = nogc.cc @@ -156,10 +156,11 @@ gnu/classpath/jdwp/processor.lo \ gnu/classpath/jdwp/transport.lo gnu/classpath/jdwp/util.lo \ gnu/gcj.lo gnu/gcj/convert.lo gnu/gcj/io.lo gnu/gcj/runtime.lo \ - gnu/gcj/util.lo gnu/java/awt.lo gnu/java/awt/color.lo \ - gnu/java/awt/image.lo gnu/java/awt/peer.lo gnu/java/io.lo \ - gnu/java/lang.lo gnu/java/lang/reflect.lo gnu/java/locale.lo \ - gnu/java/math.lo gnu/java/net.lo gnu/java/net/protocol/file.lo \ + gnu/gcj/tools/gc_analyze.lo gnu/gcj/util.lo gnu/java/awt.lo \ + gnu/java/awt/color.lo gnu/java/awt/image.lo \ + gnu/java/awt/peer.lo gnu/java/io.lo gnu/java/lang.lo \ + gnu/java/lang/reflect.lo gnu/java/locale.lo gnu/java/math.lo \ + gnu/java/net.lo gnu/java/net/protocol/file.lo \ gnu/java/net/protocol/ftp.lo gnu/java/net/protocol/http.lo \ gnu/java/net/protocol/https.lo gnu/java/net/protocol/jar.lo \ gnu/java/nio.lo gnu/java/nio/channels.lo \ @@ -256,7 +257,7 @@ 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/net/natPlainDatagramSocketImpl.cc \ gnu/java/net/natPlainSocketImpl.cc \ gnu/java/net/protocol/core/natCoreInputStream.cc \ @@ -297,7 +298,7 @@ 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/net/natPlainDatagramSocketImpl.lo \ gnu/java/net/natPlainSocketImpl.lo \ gnu/java/net/protocol/core/natCoreInputStream.lo \ @@ -346,6 +347,16 @@ libgij_la_OBJECTS = $(am_libgij_la_OBJECTS) binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am_gc_analyze_OBJECTS = gnu/gcj/tools/gc_analyze/BlockMap.$(OBJEXT) \ + gnu/gcj/tools/gc_analyze/BytePtr.$(OBJEXT) \ + gnu/gcj/tools/gc_analyze/ItemList.$(OBJEXT) \ + gnu/gcj/tools/gc_analyze/MemoryAnalyze.$(OBJEXT) \ + gnu/gcj/tools/gc_analyze/MemoryMap.$(OBJEXT) \ + gnu/gcj/tools/gc_analyze/ObjectMap.$(OBJEXT) \ + gnu/gcj/tools/gc_analyze/SymbolLookup.$(OBJEXT) \ + gnu/gcj/tools/gc_analyze/SymbolTable.$(OBJEXT) \ + gnu/gcj/tools/gc_analyze/ToolPrefix.$(OBJEXT) +gc_analyze_OBJECTS = $(am_gc_analyze_OBJECTS) am_gcj_dbtool_OBJECTS = gnu/gcj/tools/gcj_dbtool/Main.$(OBJEXT) \ gnu/gcj/tools/gcj_dbtool/natMain.$(OBJEXT) gcj_dbtool_OBJECTS = $(am_gcj_dbtool_OBJECTS) @@ -392,15 +403,17 @@ $(lib_gnu_java_awt_peer_gtk_la_SOURCES) \ $(lib_gnu_java_awt_peer_qt_la_SOURCES) $(libgcj_la_SOURCES) \ $(libgcjawt_la_SOURCES) $(libgij_la_SOURCES) \ - $(gcj_dbtool_SOURCES) $(gen_from_JIS_SOURCES) $(gij_SOURCES) \ - $(grmic_SOURCES) $(grmiregistry_SOURCES) $(jv_convert_SOURCES) + $(gc_analyze_SOURCES) $(gcj_dbtool_SOURCES) \ + $(gen_from_JIS_SOURCES) $(gij_SOURCES) $(grmic_SOURCES) \ + $(grmiregistry_SOURCES) $(jv_convert_SOURCES) DIST_SOURCES = $(lib_gnu_awt_xlib_la_SOURCES) \ $(lib_gnu_java_awt_peer_gtk_la_SOURCES) \ $(lib_gnu_java_awt_peer_qt_la_SOURCES) \ $(am__libgcj_la_SOURCES_DIST) $(libgcjawt_la_SOURCES) \ - $(libgij_la_SOURCES) $(gcj_dbtool_SOURCES) \ - $(am__gen_from_JIS_SOURCES_DIST) $(gij_SOURCES) \ - $(grmic_SOURCES) $(grmiregistry_SOURCES) $(jv_convert_SOURCES) + $(libgij_la_SOURCES) $(gc_analyze_SOURCES) \ + $(gcj_dbtool_SOURCES) $(am__gen_from_JIS_SOURCES_DIST) \ + $(gij_SOURCES) $(grmic_SOURCES) $(grmiregistry_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 \ @@ -1212,8 +1225,21 @@ gnu/gcj/runtime/SystemClassLoader.java gnu_gcj_runtime_header_files = $(patsubst %.java,%.h,$(gnu_gcj_runtime_source_files)) +gnu_gcj_tools_gc_analyze_source_files = \ +gnu/gcj/tools/gc_analyze/BlockMap.java \ +gnu/gcj/tools/gc_analyze/BytePtr.java \ +gnu/gcj/tools/gc_analyze/ItemList.java \ +gnu/gcj/tools/gc_analyze/MemoryAnalyze.java \ +gnu/gcj/tools/gc_analyze/MemoryMap.java \ +gnu/gcj/tools/gc_analyze/ObjectMap.java \ +gnu/gcj/tools/gc_analyze/SymbolLookup.java \ +gnu/gcj/tools/gc_analyze/SymbolTable.java \ +gnu/gcj/tools/gc_analyze/ToolPrefix.java + +gnu_gcj_tools_gc_analyze_header_files = $(patsubst %.java,%.h,$(gnu_gcj_tools_gc_analyze_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_header_files = $(patsubst %.java,%.h,$(gnu_gcj_util_source_files)) gnu_gcj_xlib_source_files = \ @@ -6275,6 +6301,7 @@ gnu/gcj/convert.list \ gnu/gcj/io.list \ gnu/gcj/runtime.list \ + gnu/gcj/tools/gc_analyze.list \ gnu/gcj/util.list \ gnu/java/awt.list \ gnu/java/awt/color.list \ @@ -6470,6 +6497,7 @@ $(gnu_gcj_convert_header_files) \ $(gnu_gcj_io_header_files) \ $(gnu_gcj_runtime_header_files) \ + $(gnu_gcj_tools_gc_analyze_header_files) \ $(gnu_gcj_util_header_files) \ $(gnu_java_awt_header_files) \ $(gnu_java_awt_color_header_files) \ @@ -6717,6 +6745,23 @@ gcj_dbtool_LINK = $(GCJLINK) gcj_dbtool_LDADD = -L$(here)/.libs libgcj.la gcj_dbtool_DEPENDENCIES = libgcj.la libgcj.spec +gc_analyze_SOURCES = \ +gnu/gcj/tools/gc_analyze/BlockMap.java \ +gnu/gcj/tools/gc_analyze/BytePtr.java \ +gnu/gcj/tools/gc_analyze/ItemList.java \ +gnu/gcj/tools/gc_analyze/MemoryAnalyze.java \ +gnu/gcj/tools/gc_analyze/MemoryMap.java \ +gnu/gcj/tools/gc_analyze/ObjectMap.java \ +gnu/gcj/tools/gc_analyze/SymbolLookup.java \ +gnu/gcj/tools/gc_analyze/SymbolTable.java \ +gnu/gcj/tools/gc_analyze/ToolPrefix.java + +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 libgij.la +gc_analyze_DEPENDENCIES = libgij.la gij_SOURCES = gij_LDFLAGS = -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS) gij_LINK = $(GCJLINK) @@ -6754,6 +6799,7 @@ 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/net/natPlainDatagramSocketImpl.cc \ gnu/java/net/natPlainSocketImpl.cc \ @@ -7100,6 +7146,8 @@ @: > 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) @@ -7330,6 +7378,42 @@ echo " rm -f $$p $$f"; \ rm -f $$p $$f ; \ done +gnu/gcj/tools/gc_analyze/$(am__dirstamp): + @$(mkdir_p) gnu/gcj/tools/gc_analyze + @: > gnu/gcj/tools/gc_analyze/$(am__dirstamp) +gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp): + @$(mkdir_p) gnu/gcj/tools/gc_analyze/$(DEPDIR) + @: > gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/tools/gc_analyze/BlockMap.$(OBJEXT): \ + gnu/gcj/tools/gc_analyze/$(am__dirstamp) \ + gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/tools/gc_analyze/BytePtr.$(OBJEXT): \ + gnu/gcj/tools/gc_analyze/$(am__dirstamp) \ + gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/tools/gc_analyze/ItemList.$(OBJEXT): \ + gnu/gcj/tools/gc_analyze/$(am__dirstamp) \ + gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/tools/gc_analyze/MemoryAnalyze.$(OBJEXT): \ + gnu/gcj/tools/gc_analyze/$(am__dirstamp) \ + gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/tools/gc_analyze/MemoryMap.$(OBJEXT): \ + gnu/gcj/tools/gc_analyze/$(am__dirstamp) \ + gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/tools/gc_analyze/ObjectMap.$(OBJEXT): \ + gnu/gcj/tools/gc_analyze/$(am__dirstamp) \ + gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/tools/gc_analyze/SymbolLookup.$(OBJEXT): \ + gnu/gcj/tools/gc_analyze/$(am__dirstamp) \ + gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/tools/gc_analyze/SymbolTable.$(OBJEXT): \ + gnu/gcj/tools/gc_analyze/$(am__dirstamp) \ + gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/tools/gc_analyze/ToolPrefix.$(OBJEXT): \ + gnu/gcj/tools/gc_analyze/$(am__dirstamp) \ + gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) +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) @@ -7423,10 +7507,21 @@ -rm -f gnu/gcj/runtime/natStringBuffer.lo -rm -f gnu/gcj/runtime/natSystemClassLoader.$(OBJEXT) -rm -f gnu/gcj/runtime/natSystemClassLoader.lo + -rm -f gnu/gcj/tools/gc_analyze/BlockMap.$(OBJEXT) + -rm -f gnu/gcj/tools/gc_analyze/BytePtr.$(OBJEXT) + -rm -f gnu/gcj/tools/gc_analyze/ItemList.$(OBJEXT) + -rm -f gnu/gcj/tools/gc_analyze/MemoryAnalyze.$(OBJEXT) + -rm -f gnu/gcj/tools/gc_analyze/MemoryMap.$(OBJEXT) + -rm -f gnu/gcj/tools/gc_analyze/ObjectMap.$(OBJEXT) + -rm -f gnu/gcj/tools/gc_analyze/SymbolLookup.$(OBJEXT) + -rm -f gnu/gcj/tools/gc_analyze/SymbolTable.$(OBJEXT) + -rm -f gnu/gcj/tools/gc_analyze/ToolPrefix.$(OBJEXT) -rm -f gnu/gcj/tools/gcj_dbtool/Main.$(OBJEXT) -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) @@ -7597,9 +7692,19 @@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natSharedLibLoader.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natStringBuffer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natSystemClassLoader.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gc_analyze/$(DEPDIR)/BlockMap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gc_analyze/$(DEPDIR)/BytePtr.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gc_analyze/$(DEPDIR)/ItemList.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gc_analyze/$(DEPDIR)/MemoryAnalyze.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gc_analyze/$(DEPDIR)/MemoryMap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gc_analyze/$(DEPDIR)/ObjectMap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gc_analyze/$(DEPDIR)/SymbolLookup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gc_analyze/$(DEPDIR)/SymbolTable.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gc_analyze/$(DEPDIR)/ToolPrefix.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gcj_dbtool/$(DEPDIR)/Main.Po@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@ @@ -8290,6 +8395,8 @@ -rm -f gnu/gcj/io/$(am__dirstamp) -rm -f gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp) -rm -f gnu/gcj/runtime/$(am__dirstamp) + -rm -f gnu/gcj/tools/gc_analyze/$(DEPDIR)/$(am__dirstamp) + -rm -f gnu/gcj/tools/gc_analyze/$(am__dirstamp) -rm -f gnu/gcj/tools/gcj_dbtool/$(DEPDIR)/$(am__dirstamp) -rm -f gnu/gcj/tools/gcj_dbtool/$(am__dirstamp) -rm -f gnu/gcj/util/$(DEPDIR)/$(am__dirstamp) @@ -8341,7 +8448,7 @@ distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf ./$(DEPDIR) classpath/native/jawt/$(DEPDIR) gnu/classpath/$(DEPDIR) gnu/gcj/$(DEPDIR) gnu/gcj/convert/$(DEPDIR) gnu/gcj/io/$(DEPDIR) gnu/gcj/runtime/$(DEPDIR) gnu/gcj/tools/gcj_dbtool/$(DEPDIR) gnu/gcj/util/$(DEPDIR) gnu/gcj/xlib/$(DEPDIR) gnu/java/lang/$(DEPDIR) gnu/java/net/$(DEPDIR) gnu/java/net/protocol/core/$(DEPDIR) gnu/java/nio/$(DEPDIR) gnu/java/nio/channels/$(DEPDIR) java/io/$(DEPDIR) java/lang/$(DEPDIR) java/lang/ref/$(DEPDIR) java/lang/reflect/$(DEPDIR) java/net/$(DEPDIR) java/nio/$(DEPDIR) java/nio/channels/$(DEPDIR) java/text/$(DEPDIR) java/util/$(DEPDIR) java/util/logging/$(DEPDIR) java/util/zip/$(DEPDIR) + -rm -rf ./$(DEPDIR) classpath/native/jawt/$(DEPDIR) gnu/classpath/$(DEPDIR) gnu/gcj/$(DEPDIR) gnu/gcj/convert/$(DEPDIR) gnu/gcj/io/$(DEPDIR) gnu/gcj/runtime/$(DEPDIR) gnu/gcj/tools/gc_analyze/$(DEPDIR) gnu/gcj/tools/gcj_dbtool/$(DEPDIR) gnu/gcj/util/$(DEPDIR) gnu/gcj/xlib/$(DEPDIR) gnu/java/lang/$(DEPDIR) gnu/java/net/$(DEPDIR) gnu/java/net/protocol/core/$(DEPDIR) gnu/java/nio/$(DEPDIR) gnu/java/nio/channels/$(DEPDIR) java/io/$(DEPDIR) java/lang/$(DEPDIR) java/lang/ref/$(DEPDIR) java/lang/reflect/$(DEPDIR) java/net/$(DEPDIR) java/nio/$(DEPDIR) java/nio/channels/$(DEPDIR) java/text/$(DEPDIR) java/util/$(DEPDIR) java/util/logging/$(DEPDIR) java/util/zip/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-local distclean-tags @@ -8372,7 +8479,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf ./$(DEPDIR) classpath/native/jawt/$(DEPDIR) gnu/classpath/$(DEPDIR) gnu/gcj/$(DEPDIR) gnu/gcj/convert/$(DEPDIR) gnu/gcj/io/$(DEPDIR) gnu/gcj/runtime/$(DEPDIR) gnu/gcj/tools/gcj_dbtool/$(DEPDIR) gnu/gcj/util/$(DEPDIR) gnu/gcj/xlib/$(DEPDIR) gnu/java/lang/$(DEPDIR) gnu/java/net/$(DEPDIR) gnu/java/net/protocol/core/$(DEPDIR) gnu/java/nio/$(DEPDIR) gnu/java/nio/channels/$(DEPDIR) java/io/$(DEPDIR) java/lang/$(DEPDIR) java/lang/ref/$(DEPDIR) java/lang/reflect/$(DEPDIR) java/net/$(DEPDIR) java/nio/$(DEPDIR) java/nio/channels/$(DEPDIR) java/text/$(DEPDIR) java/util/$(DEPDIR) java/util/logging/$(DEPDIR) java/util/zip/$(DEPDIR) + -rm -rf ./$(DEPDIR) classpath/native/jawt/$(DEPDIR) gnu/classpath/$(DEPDIR) gnu/gcj/$(DEPDIR) gnu/gcj/convert/$(DEPDIR) gnu/gcj/io/$(DEPDIR) gnu/gcj/runtime/$(DEPDIR) gnu/gcj/tools/gc_analyze/$(DEPDIR) gnu/gcj/tools/gcj_dbtool/$(DEPDIR) gnu/gcj/util/$(DEPDIR) gnu/gcj/xlib/$(DEPDIR) gnu/java/lang/$(DEPDIR) gnu/java/net/$(DEPDIR) gnu/java/net/protocol/core/$(DEPDIR) gnu/java/nio/$(DEPDIR) gnu/java/nio/channels/$(DEPDIR) java/io/$(DEPDIR) java/lang/$(DEPDIR) java/lang/ref/$(DEPDIR) java/lang/reflect/$(DEPDIR) java/net/$(DEPDIR) java/nio/$(DEPDIR) java/nio/channels/$(DEPDIR) java/text/$(DEPDIR) java/util/$(DEPDIR) java/util/logging/$(DEPDIR) java/util/zip/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic @@ -8630,6 +8737,16 @@ -include gnu/gcj/runtime.deps +gnu/gcj/tools/gc_analyze.list: $(gnu_gcj_tools_gc_analyze_source_files) + @$(mkinstalldirs) $(dir $@) + @for file in $(gnu_gcj_tools_gc_analyze_source_files); do \ + if test -f $(srcdir)/$$file; then \ + echo $(srcdir)/$$file; \ + else echo $$file; fi; \ + done > gnu/gcj/tools/gc_analyze.list + +-include gnu/gcj/tools/gc_analyze.deps + gnu/gcj/util.list: $(gnu_gcj_util_source_files) @$(mkinstalldirs) $(dir $@) @for file in $(gnu_gcj_util_source_files); do \ Index: configure.ac =================================================================== --- configure.ac (revision 113530) +++ configure.ac (working copy) @@ -907,10 +907,14 @@ if test x"$build" = x"$host"; 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 Index: sources.am =================================================================== --- sources.am (revision 113530) +++ sources.am (working copy) @@ -579,8 +579,33 @@ -include gnu/gcj/runtime.deps +gnu_gcj_tools_gc_analyze_source_files = \ +gnu/gcj/tools/gc_analyze/BlockMap.java \ +gnu/gcj/tools/gc_analyze/BytePtr.java \ +gnu/gcj/tools/gc_analyze/ItemList.java \ +gnu/gcj/tools/gc_analyze/MemoryAnalyze.java \ +gnu/gcj/tools/gc_analyze/MemoryMap.java \ +gnu/gcj/tools/gc_analyze/ObjectMap.java \ +gnu/gcj/tools/gc_analyze/SymbolLookup.java \ +gnu/gcj/tools/gc_analyze/SymbolTable.java \ +gnu/gcj/tools/gc_analyze/ToolPrefix.java + +gnu_gcj_tools_gc_analyze_header_files = $(patsubst %.java,%.h,$(gnu_gcj_tools_gc_analyze_source_files)) + +gnu/gcj/tools/gc_analyze.list: $(gnu_gcj_tools_gc_analyze_source_files) + @$(mkinstalldirs) $(dir $@) + @for file in $(gnu_gcj_tools_gc_analyze_source_files); do \ + if test -f $(srcdir)/$$file; then \ + echo $(srcdir)/$$file; \ + else echo $$file; fi; \ + done > gnu/gcj/tools/gc_analyze.list + +-include gnu/gcj/tools/gc_analyze.deps + + gnu_gcj_util_source_files = \ -gnu/gcj/util/Debug.java +gnu/gcj/util/Debug.java \ +gnu/gcj/util/GCInfo.java gnu_gcj_util_header_files = $(patsubst %.java,%.h,$(gnu_gcj_util_source_files)) @@ -7849,6 +7874,7 @@ gnu/gcj/convert.list \ gnu/gcj/io.list \ gnu/gcj/runtime.list \ + gnu/gcj/tools/gc_analyze.list \ gnu/gcj/util.list \ gnu/java/awt.list \ gnu/java/awt/color.list \ @@ -8044,6 +8070,7 @@ $(gnu_gcj_convert_header_files) \ $(gnu_gcj_io_header_files) \ $(gnu_gcj_runtime_header_files) \ + $(gnu_gcj_tools_gc_analyze_header_files) \ $(gnu_gcj_util_header_files) \ $(gnu_java_awt_header_files) \ $(gnu_java_awt_color_header_files) \ Index: include/config.h.in =================================================================== --- include/config.h.in (revision 113530) +++ include/config.h.in (working copy) @@ -211,6 +211,9 @@ /* 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 @@ -351,6 +354,9 @@ /* 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: Makefile.am =================================================================== --- Makefile.am (revision 113530) +++ Makefile.am (working copy) @@ -74,7 +74,7 @@ ## For now, only on native systems. FIXME. if NATIVE -bin_PROGRAMS = jv-convert gij grmic grmiregistry gcj-dbtool +bin_PROGRAMS = jv-convert gij grmic grmiregistry gcj-dbtool gc_analyze ## It is convenient to actually build and install the default database ## when gcj-dbtool is available. @@ -731,6 +731,29 @@ ## linking this program. gcj_dbtool_DEPENDENCIES = libgcj.la libgcj.spec +gc_analyze_SOURCES = \ +gnu/gcj/tools/gc_analyze/BlockMap.java \ +gnu/gcj/tools/gc_analyze/BytePtr.java \ +gnu/gcj/tools/gc_analyze/ItemList.java \ +gnu/gcj/tools/gc_analyze/MemoryAnalyze.java \ +gnu/gcj/tools/gc_analyze/MemoryMap.java \ +gnu/gcj/tools/gc_analyze/ObjectMap.java \ +gnu/gcj/tools/gc_analyze/SymbolLookup.java \ +gnu/gcj/tools/gc_analyze/SymbolTable.java \ +gnu/gcj/tools/gc_analyze/ToolPrefix.java + +## 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 libgij.la +## Depend on the spec file to make sure it is up to date before +## linking this program. +gc_analyze_DEPENDENCIES = libgij.la + 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 @@ -786,6 +809,7 @@ 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/net/natPlainDatagramSocketImpl.cc \ gnu/java/net/natPlainSocketImpl.cc \ New files follow... --- /dev/null 2006-04-22 03:37:59.501056688 -0700 +++ gnu/gcj/util/GCInfo.java 2006-05-04 10:18:31.000000000 -0700 @@ -0,0 +1,51 @@ +/* GCInfo.java -- Support for creating heap dumps. + Copyright (C) 2006 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() + { + } + + public static synchronized void dump(String name) + { + dump0(name); + } + + public static native void dump0(String name); + + + /** + * Create a heap dump. + * + * @param namePrefix The filename prefix for the dump files. + */ + public static synchronized void enumerate(String namePrefix) + { + enumerate0(namePrefix); + } + + public 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. + */ + public static synchronized void setOOMDump(String namePrefix) + { + setOOMDump0(namePrefix); + } + + public static native void setOOMDump0(String namePrefix); + +} --- /dev/null 2006-04-22 03:37:59.501056688 -0700 +++ gnu/gcj/util/natGCInfo.cc 2006-05-04 10:31:33.000000000 -0700 @@ -0,0 +1,461 @@ +/* natGCInfo.cc -- Native portion of support for creating heap dumps. + Copyright (C) 2006 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 + +#include + +#include + +#ifdef HAVE_PROC_SELF_MAPS +// +// If /proc/self/maps does not exist we assume we are doomed and do nothing. +// +#include +#include +#include +#include +#include +#include + +// +// 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 = %d, 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 gnu +{ + namespace gcj + { + namespace util + { + class 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); + }; + } + } +} + +::gnu::gcj::util::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 +::gnu::gcj::util::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 && (strlen(buffer) > (colon - buffer) + 2U)) + { + 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 +::gnu::gcj::util::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 +::gnu::gcj::util::GC_enumerator::enumerate_callback_adaptor(struct hblk *h, + word dummy) +{ + GC_enumerator* pinfo = (GC_enumerator*)dummy; + pinfo->enumerate_callback(h); +} + +void +::gnu::gcj::util::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 size = bytes; // size + 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 = %d, kind = %d, " + "klass = %#lx, data = %#lx\n", + inUse, (unsigned long)ptr, size, 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; ilength() + 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(%d) called\n", size); + gc_ok--; + ::gnu::gcj::util::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 + --- /dev/null 2006-04-22 03:37:59.501056688 -0700 +++ gnu/gcj/tools/gc_analyze/BlockMap.java 2006-05-04 10:15:42.000000000 -0700 @@ -0,0 +1,225 @@ +/* BlockMap.java -- Container for information on GC maintained memory blocks. + Copyright (C) 2006 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.Iterator; +import java.util.Map; +import java.util.TreeMap; + +class BlockMap +{ + static final int HBLKSIZE = 4096; + + class SizeKind implements Comparable + { + int size; + int kind; + + public SizeKind(int size, int kind) + { + this.size = size; + this.kind = kind; + } + + public int compareTo(Object b) + { + SizeKind ska = this; + SizeKind skb = (SizeKind)b; + if (ska.size != skb.size) + return ska.size - skb.size; + return ska.kind - skb.kind; + } + } + + class PtrMarks + { + int ptr; + int marks; + public PtrMarks(int ptr, int marks) + { + this.ptr = ptr; + this.marks = marks; + } + } + + private TreeMap map = new TreeMap(); + + public Iterator iterator() + { + return map.entrySet().iterator(); + } + + public BlockMap(BufferedReader reader) throws IOException + { + for (;;) + { + String s = reader.readLine(); + if (s.charAt(0) == '#') + continue; + if (s == null) + break; + 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(","); + int ptr = 0; + int kind = 0, size = 0, marks = 0; + for (int i=0; i 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); + } + //System.out.println(); + } // 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)); + } +} --- /dev/null 2006-04-22 03:37:59.501056688 -0700 +++ gnu/gcj/tools/gc_analyze/BytePtr.java 2006-05-04 10:15:42.000000000 -0700 @@ -0,0 +1,110 @@ +/* BytePtr.java -- Container for bytes from a memory image. + Copyright (C) 2006 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 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()); + } +} --- /dev/null 2006-04-22 03:37:59.501056688 -0700 +++ gnu/gcj/tools/gc_analyze/ItemList.java 2006-05-04 10:15:42.000000000 -0700 @@ -0,0 +1,73 @@ +/* ItemList.java -- Maps all objects keyed by their addresses. + Copyright (C) 2006 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.Iterator; +import java.util.Map; +import java.util.TreeMap; + +class ItemList +{ + public ItemList() + { + } + + private TreeMap map; + + public void add(ObjectMap.ObjectItem item) + { + if (map == null) + map = new TreeMap(); + Long x = new Long(item.klass); + HashMap list = (HashMap)map.get(x);; + if (list == null) + { + list = new HashMap(); + map.put(x, list); + } + Integer count = (Integer)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 (Iterator it = map.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry me = (Map.Entry)it.next(); + HashMap list = (HashMap)me.getValue(); + boolean first = true; + for (Iterator it2 = list.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry me2 = (Map.Entry)it2.next(); + ObjectMap.ObjectItem item = (ObjectMap.ObjectItem)me2.getKey(); + Integer count = (Integer)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(); + } + } + } +} --- /dev/null 2006-04-22 03:37:59.501056688 -0700 +++ gnu/gcj/tools/gc_analyze/MemoryAnalyze.java 2006-05-04 10:15:42.000000000 -0700 @@ -0,0 +1,438 @@ +/* MemoryAnalyze.java -- Analyzes a libgcj heap dump. + Copyright (C) 2006 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.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; + 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 list, + Comparator 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 void usage() + { + System.out.println("usage: MemoryAnalyze [-v] [-p tool-prefix] [-d filename]"); + System.out.println(" -v == verbose; requires filename.bytes"); + System.out.println(" -p tool-prefix; A string prepended to nm and readelf to obtain\n" + + " target specific versions of these commands"); + System.out.println(); + System.exit(1); + } + + static class SubstringComparator implements Comparator + { + 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(Object o1, Object o2) + { + String s1 = (String)o1; + if (end == 0) + s1 = s1.substring(begin); + else + s1 = s1.substring(begin, end); + String s2 = (String)o2; + if (end == 0) + s2 = s2.substring(begin); + else + s2 = s2.substring(begin, end); + int i = s1.compareTo(s2); + if (reverse) + return -i; + return i; + } + } + + public static void main(String[] args) + { + class Info + { + int size; + int count; + } + int total_space = 0; + + boolean verbose = false; + try + { + // parse command-line + String directory = "."; + String filename = null; + for (int i=0; i to Range + + returns filename given address + returns offset given address + returns BytePtr given address (new) + +*/ +class MemoryMap +{ + static class RangeComparator implements Comparator + { + public int compare(Object arg0, Object arg1) + { + return compare((Range)arg0, (Range)arg1); + } + + public static 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; + } + } + + // String filename -> Range + TreeSet map = new TreeSet(new RangeComparator()); + HashMap symbolTables = new HashMap(); + String prefix; + ByteOrder byteOrder; + int wordSize; + + public MemoryMap(BufferedReader reader, + String prefix, + String rawFileName) throws IOException + { + this.prefix = prefix; + + 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; + } + long address = Long.parseLong(s.substring(0,8), 16); + long address2 = Long.parseLong(s.substring(9,17), 16); + long offset; + try + { + offset = Long.parseLong(s.substring(23, 23+8), 16); + } + catch (Exception e) + { + offset = 0; + } + int end = s.indexOf('/'); + + if (end > 0) + { + String file = s.substring(end); + if (file.startsWith("/dev/")) + { + // System.out.println("skipping: "+file); + continue; + } + Range r = new Range(address, address2, file, offset); + if (offset == 0) + { + // Read the file's symbol table + try { + File f = 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 (Iterator it=map.iterator(); it.hasNext(); ) + { + Range r = (Range)it.next(); + + 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 t = map.tailSet(r); + if (t.isEmpty()) + return null; + Range c = (Range)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; + } + + File fileForName(String filename) + { + File f = new File(prefix + 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; + } + + + // returns bytearray which includes given address + BytePtr getBytePtr(long addr, int length) throws IOException + { + Range r = getRange(addr); + + if (null == r) + return null; + + File f = 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 = (SymbolTable)symbolTables.get(r.filename); + if (st == null) + return null; + + // Apply relocation + addr -= st.relocation; + + return st.getSymbol(addr); + } + + // search all symbol tables + // return -1 if none found + long getAddress(SymbolLookup lookup, String symbol) throws IOException + { + // for (Iterator it=map.entrySet().iterator(); it.hasNext(); ) + // { + // Map.Entry me = (Map.Entry)it.next(); + // String file = (String)me.getKey(); + // SymbolTable st = lookup.getSymbolTable(file); + // int a = st.getAddress(symbol); + // if (a != -1) + // return a; + // } + return -1; + } +} --- /dev/null 2006-04-22 03:37:59.501056688 -0700 +++ gnu/gcj/tools/gc_analyze/ObjectMap.java 2006-05-04 10:15:42.000000000 -0700 @@ -0,0 +1,145 @@ +/* ObjectMap.java -- Contains a map of all objects keyed by their addresses. + Copyright (C) 2006 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 +{ + + 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 m_reference; // object at m_reference points to this + + ItemList points_to = new ItemList(); + ItemList pointed_by = new ItemList(); + + // for persistance + int m_offset; // address when reloaded (can't be zero -- special value) + } + + private TreeMap map = new TreeMap(); + + public Iterator iterator() + { + return map.entrySet().iterator(); + } + + public ObjectItem get(long ptr) + { + ObjectItem item = (ObjectItem)map.get(new Long(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 1) + item.klass = Long.parseLong(last.substring(2),16); + else + item.klass = Integer.parseInt(last,16); + break; + case 5: + try + { + item.data = + Integer.parseInt(last.substring(2), 16); + } + catch (Exception e) + { + // System.out.println("last = "+last); + item.data = 0; + } + break; + } + } + item.ptr = ptr; + map.put(new Long(ptr), item); + } // inner loop + } // started inner loop + } // outer loop - finding begin + for (Iterator it= this.iterator(); it.hasNext(); ) + { + Map.Entry me = (Map.Entry)it.next(); + // int ptr = ((Integer)me.getKey()).intValue(); + ObjectItem item = (ObjectItem)me.getValue(); + if (item.data != 0) { + // see if data is a pointer to a block + ObjectItem referenced = + (ObjectItem)map.get(new Long(item.data)); + if (referenced != null) + { + referenced.m_reference = item; + } + } + } + } // memoryMap + + public void dump() + { + for (Iterator it = iterator(); it.hasNext(); ) + { + Map.Entry me = (Map.Entry)it.next(); + int ptr = ((Integer)me.getKey()).intValue(); + ObjectItem item = (ObjectItem)me.getValue(); + System.out.println("ptr = " + Integer.toHexString(ptr) + + ", size = " + item.size + + ", klass = " + Long.toHexString(item.klass) + + ", kind = " + item.kind + + ", data = " + item.data); + } + } +} --- /dev/null 2006-04-22 03:37:59.501056688 -0700 +++ gnu/gcj/tools/gc_analyze/SymbolLookup.java 2006-05-04 10:15:42.000000000 -0700 @@ -0,0 +1,110 @@ +/* SymbolLookup.java -- Finds class names by analyzing memory. + Copyright (C) 2006 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 prefix, + String rawFileName) + throws IOException + { + memoryMap = new MemoryMap(reader, prefix, rawFileName); + } + + public String decodeUTF8(long address) throws IOException + { + if (address == 0) + return null; + + BytePtr utf8 = memoryMap.getBytePtr(address, 64); + + if (utf8 == null) + return null; + + int len = utf8.getShort(1); + + if (len <= 0) + 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 + } + + return sb.toString(); + } + + /** + * + * @param address + * @return + * @throws IOException + */ + 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); + } + + long getAddress(String symbol) throws IOException + { + return memoryMap.getAddress(this, symbol); + } + + BytePtr getBytePtr(long addr, int length) throws IOException + { + return memoryMap.getBytePtr(addr, length); + } +} --- /dev/null 2006-04-22 03:37:59.501056688 -0700 +++ gnu/gcj/tools/gc_analyze/SymbolTable.java 2006-05-04 10:15:42.000000000 -0700 @@ -0,0 +1,213 @@ +/* SymbolTable.java -- Maintains a mapping of addresses to names. + Copyright (C) 2006 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.Iterator; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +class SymbolTable +{ + // Long address->String name + private HashMap map = new HashMap(); + + // Reverse + // String name -> Long address + // used for RelocateImage + private HashMap reverse = new HashMap(); + + 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 = Long.parseLong(addr, 16); + 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 (Iterator it = map.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry me = (Map.Entry)it.next(); + long address = ((Long)me.getKey()).intValue(); + String symbol = (String)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))); + } + } + } + /* + public int addressOf(String symbol) + { + for (Iterator it = m_map.entrySet().iterator(); it.hasNext(); ) { + Map.Entry me = (Map.Entry)it.next(); + int address = ((Integer)me.getKey()).intValue(); + if (getSymbol(address).compareTo(symbol) == 0) + return address; + } + return 0; + } + */ + + + private static String demangle(String symbol) + { + StringBuilder sb = new StringBuilder(); + for (int i=0; i '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 = (String)map.get(new Long(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 = (Long)reverse.get(symbol); + if (address == null) + return -1; + return address.longValue(); + } +} --- /dev/null 2006-04-22 03:37:59.501056688 -0700 +++ gnu/gcj/tools/gc_analyze/ToolPrefix.java 2006-05-04 10:15:42.000000000 -0700 @@ -0,0 +1,15 @@ +/* ToolPrefix.java -- Container of the toolPrefix String. + Copyright (C) 2006 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; + +class ToolPrefix +{ + static String toolPrefix = ""; +}