This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Throwable stack trace printing again


Hi,

I rewrote Throwable stack trace (printing) support. With this patch the
Junk example mentioned in the Throwable javadoc gives (when compiled
with -g):

HighLevelException: MidLevelException: LowLevelException
   at Junk.a() (/tmp/Junk.java:21)
   at Junk.main(java.lang.String[]) (/tmp/Junk.java:7)
Caused by: MidLevelException: LowLevelException
   at Junk.c() (/tmp/Junk.java:36)
   at Junk.b() (/tmp/Junk.java:29)
   at Junk.a() (/tmp/Junk.java:19)
   ...1 more
Caused by: LowLevelException
   at Junk.e() (/tmp/Junk.java:46)
   at Junk.d() (/tmp/Junk.java:44)
   at Junk.c() (/tmp/Junk.java:34)
   ...3 more

The patch tries to accomplish a couple of things:
- Simplify and optimize the stack trace printing algorithm which is done
by refactoring the code and using a StringBuffer. This also solves the
bug I mentioned a couple of days ago which was caused by forgetting to
flush the PrintWriter. Now no temporary PrintWriter is created at all.
- Separating the VM dependent part from the VM independent part by
moving fillInStackTrace() and getStackTrace() into a new package final
class VMThrowable. This should make Throwable easier to share with other
VMs based on GNU Classpath.
- Do as much as possible in java which makes manipulating the
StackTraceElement[] that much easier. I followed the advise of Bryce and
store the raw stack trace as an long[] so only two short native methods
are needed. The resulting stack traces look much more like traditional
java stack traces now.

2002-07-26  Mark Wielaard  <mark@klomp.org>

    * Makefile.am (libgcj_la_SOURCES): Remove name-finder.cc.
    (core_java_source_files): Add VMThrowable.java and NameFinder.java
    (nat_source_files): Add natNameFinder.cc.
    * Makefile.in: Regenerate.
    * prims.cc: Use trace_enabled from VMThrowable.
    * name-finder.cc: Removed.
    * gcj/javaprims.h: Add class VMThrowable.
    * gnu/gcj/runtime/NameFinder.java: New file.
    * gnu/gcj/runtime/natNameFinder.cc: Likewise.
    * include/name-finder.h: Removed.
    * java/lang/Throwable.java (printStackTrace (PrintStream)): Use new
    method stackTraceString().
    (printStackTrace (PrintWriter)): Likewise.
    (stackTraceString): Complete rewrite of old printStackTrace using
    StringBuffer.
    (stackTraceStringBuffer): New helper method for stackTraceString().
    (fillInStackTrace): Delegate to VMTrowable.
    (getStackTrace): Likewise.
    (getStackTrace0): Removed. 
    (trace_enabled, stackTraceBytes): Moved to new VMThrowable.java.
    * java/lang/VMThrowable.java: New class.
    * java/lang/natThrowable.cc (fillInStackTrace): Now part of
    VMThrowable. Put the result of backtrace() in a long[].
    (getStackTrace0): Removed.

Questions:
- Is the separation of Throwable and VMThrowable OK? I had hoped that
gcj would inline calls to a final package local class but it currently
doesn't.
- Is the conversion to/from void*/jlong correct? It works on my
i686-pc-linux-gnu and I will try it out on a powerpc-unknown-linux-gnu
machine soon, but my C knowledge is not good enough to know if this will
always work on any architecture.
- Is doing most things in java a good idea? I personally think nicer
stack traces are much more important than having working stack traces
when the runtime breaks down. And you probably have much bigger problems
then having a working printStackTrace(). But I guess not everybody loves
using gdb ;)
- OK to commit?

Cheers,

Mark
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.232
diff -u -r1.232 Makefile.am
--- Makefile.am	15 Jul 2002 16:05:13 -0000	1.232
+++ Makefile.am	26 Jul 2002 20:37:22 -0000
@@ -128,7 +128,7 @@
 x_javao_files = $(x_java_source_files:.java=.lo)
 
 libgcj_la_SOURCES = prims.cc jni.cc exception.cc \
-	resolve.cc defineclass.cc interpret.cc name-finder.cc verify.cc \
+	resolve.cc defineclass.cc interpret.cc verify.cc \
 	$(nat_source_files)
 EXTRA_libgcj_la_SOURCES = boehm.cc nogc.cc posix-threads.cc no-threads.cc \
 	win32-threads.cc posix.cc win32.cc \
@@ -1121,6 +1121,7 @@
 java/lang/VirtualMachineError.java \
 java/lang/VMClassLoader.java \
 java/lang/VMSecurityManager.java \
+java/lang/VMThrowable.java \
 java/lang/Void.java \
 java/io/BufferedInputStream.java \
 java/io/BufferedOutputStream.java \
@@ -1281,6 +1282,7 @@
 gnu/gcj/runtime/FinalizerThread.java \
 gnu/gcj/runtime/FirstThread.java \
 gnu/gcj/runtime/JNIWeakRef.java \
+gnu/gcj/runtime/NameFinder.java \
 gnu/gcj/runtime/SharedLibLoader.java \
 gnu/gcj/runtime/StringBuffer.java \
 gnu/gcj/runtime/VMClassLoader.java \
@@ -1793,6 +1795,7 @@
 gnu/gcj/protocol/core/natCoreInputStream.cc \
 gnu/gcj/runtime/natFinalizerThread.cc \
 gnu/gcj/runtime/natFirstThread.cc \
+gnu/gcj/runtime/natNameFinder.cc \
 gnu/gcj/runtime/natSharedLibLoader.cc \
 gnu/gcj/runtime/natStringBuffer.cc \
 java/io/natFile.cc \
Index: prims.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.72
diff -u -r1.72 prims.cc
--- prims.cc	10 Mar 2002 03:53:12 -0000	1.72
+++ prims.cc	26 Jul 2002 20:37:22 -0000
@@ -53,6 +53,7 @@
 #include <java/lang/NullPointerException.h>
 #include <java/lang/OutOfMemoryError.h>
 #include <java/lang/System.h>
+#include <java/lang/VMThrowable.h>
 #include <java/lang/reflect/Modifier.h>
 #include <java/io/PrintStream.h>
 #include <java/lang/UnsatisfiedLinkError.h>
@@ -910,8 +911,8 @@
   _Jv_InitPrimClass (&_Jv_voidClass,    "void",    'V', 0, &_Jv_voidVTable);
 
   // Turn stack trace generation off while creating exception objects.
-  _Jv_InitClass (&java::lang::Throwable::class$);
-  java::lang::Throwable::trace_enabled = 0;
+  _Jv_InitClass (&java::lang::VMThrowable::class$);
+  java::lang::VMThrowable::trace_enabled = 0;
   
   INIT_SEGV;
 #ifdef HANDLE_FPE
@@ -923,7 +924,7 @@
 
   no_memory = new java::lang::OutOfMemoryError;
 
-  java::lang::Throwable::trace_enabled = 1;
+  java::lang::VMThrowable::trace_enabled = 1;
 
 #ifdef USE_LTDL
   LTDL_SET_PRELOADED_SYMBOLS ();
Index: name-finder.cc
===================================================================
RCS file: name-finder.cc
diff -N name-finder.cc
--- name-finder.cc	12 Jul 2002 12:52:43 -0000	1.12
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,356 +0,0 @@
-// name-finder.cc - Convert addresses to names
-
-/* Copyright (C) 2000, 2002  Free Software Foundation, Inc
-
-   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.  */
-
-/**
- * @author Andrew Haley <aph@cygnus.com>
- * @date Jan 6  2000
- */
-
-/* _Jv_name_finder is a class wrapper around a mechanism that can
-   convert address of methods to their names and the names of files in
-   which they appear.
-
-   Right now, the only implementation of this involves running a copy
-   of addr2line, but at some point it is worth building this
-   functionality into libgcj, if only for embedded systems.  */
-
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#endif
-
-#include <config.h>
-
-#include <string.h>
-
-#include <gcj/cni.h>
-#include <jvm.h>
-#include <java/lang/Object.h>
-#include <java-threads.h>
-#include <java/lang/Throwable.h>
-#include <java/io/PrintStream.h>
-#include <java/io/PrintWriter.h>
-
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <name-finder.h>
-
-/* Create a new name finder which will perform address lookups on an
-   executable. */
-
-_Jv_name_finder::_Jv_name_finder (char *executable)
-{
-#if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
-  demangling_error = lookup_error = 0;
-
-  // Initialize file descriptors so that shutdown works properly.
-  f_pipe[0] = -1;
-  f_pipe[1] = -1;
-  b_pipe[0] = -1;
-  b_pipe[1] = -1;
-  b_pipe_fd = NULL;
-
-  f2_pipe[0] = -1;
-  f2_pipe[1] = -1;
-  b2_pipe[0] = -1;
-  b2_pipe[1] = -1;
-  b2_pipe_fd = NULL;
-
-  // addr2line helper process.
-
-  char *argv[5];
-  {
-    int arg = 0;
-#ifdef __ia64__
-    argv[arg++] = "addr2name.awk";
-#else
-    argv[arg++] = "addr2line";
-    argv[arg++] = "-f";
-    argv[arg++] = "-e";
-#endif
-    argv[arg++] = executable;
-    argv[arg] = NULL;
-  }
-
-  lookup_error |= pipe (f_pipe) < 0;
-  lookup_error |= pipe (b_pipe) < 0;
-
-  if (lookup_error)
-    return;
-
-  pid = fork ();
-  if (pid == 0)
-    {
-      close (f_pipe[1]);
-      close (b_pipe[0]);
-      dup2 (f_pipe[0], fileno (stdin));
-      dup2 (b_pipe[1], fileno (stdout));
-      execvp (argv[0], argv);
-      _exit (127);
-    }
-
-  // Close child end of pipes.  Set local descriptors to -1 so we
-  // don't try to close the fd again.
-  close (f_pipe [0]);
-  f_pipe[0] = -1;
-  close (b_pipe [1]);
-  b_pipe[1] = -1;
-
-  if (pid < 0)
-    {
-      lookup_error |= 1; 
-      return;
-    }
-
-  b_pipe_fd = fdopen (b_pipe[0], "r");
-  lookup_error |= !b_pipe_fd;
-
-  if (! lookup_error)
-    {
-      // Don't try to close the fd twice.
-      b_pipe[0] = -1;
-    }
-
-  // c++filt helper process.
-  
-  char *argv2[4];
-  argv2[0] = "c++filt";
-  argv2[1] = "-s";
-  argv2[2] = "java";
-  argv2[3] = NULL;
-
-  demangling_error |= pipe (f2_pipe) < 0;
-  demangling_error |= pipe (b2_pipe) < 0;
-
-  if (demangling_error)
-    return;
-
-  pid2 = fork ();
-  if (pid2 == 0)
-    {
-      close (f2_pipe[1]);
-      close (b2_pipe[0]);
-      dup2 (f2_pipe[0], fileno (stdin));
-      dup2 (b2_pipe[1], fileno (stdout));
-      execvp (argv2[0], argv2);
-      _exit (127);
-    }
-
-  // Close child end of pipes.  Set local descriptors to -1 so we
-  // don't try to close the fd again.
-  close (f2_pipe [0]);
-  f2_pipe[0] = -1;
-  close (b2_pipe [1]);
-  b2_pipe[1] = -1;
-
-  if (pid2 < 0)
-    {
-      demangling_error |= 1; 
-      return;
-    }
-
-  b2_pipe_fd = fdopen (b2_pipe[0], "r");
-  demangling_error |= !b2_pipe_fd;
-
-  if (! demangling_error)
-    {
-      // Don't try to close the fd twice.
-      b2_pipe[0] = -1;
-    }
-#endif
-}
-
-/* Convert a pointer to hex. */
-
-void
-_Jv_name_finder::toHex (void *p)
-{
-  typedef unsigned word_t __attribute ((mode (word)));
-  word_t n = (word_t) p;
-  int digits = sizeof (void *) * 2;
-
-  strcpy (hex, "0x");
-  for (int i = digits - 1; i >= 0; i--)
-    {
-      int digit = n % 16;
-      
-      n /= 16;
-      hex[i+2] = digit > 9 ? 'a' + digit - 10 : '0' + digit; 
-    }
-  hex [digits+2] = 0;
-}   
-
-/* Creates a StackTraceElement given a string and a filename.
-   Splits the given string into the class and method part.
-   The string s will be a demangled to a fully qualified java method string.
-   The string f will be decomposed into a file name and a possible line number.
-   The given strings will be altered.  */
-
-java::lang::StackTraceElement*
-_Jv_name_finder::createStackTraceElement(char *s, char *f)
-{
-  char *c;
-  char *class_name = NULL;
-  char *method_name = NULL;
-
-#if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
-  if (demangling_error)
-    goto fail;
-
-  demangling_error |= write (f2_pipe[1], s, strlen (s)) < 0;
-  if (demangling_error)
-    goto fail;
-  demangling_error |= write (f2_pipe[1], "\n", 1) < 0;
-  if (demangling_error)
-    goto fail;
-
-  char name[1024];
-  demangling_error |= (fgets (name, sizeof name, b2_pipe_fd) == NULL);
-  if (demangling_error)
-    goto fail;
-
-  c = strchr (name, '\n');
-  if (c)
-    *c = 0;
-  s = name;
-#endif
-
-  c = strchr (s, '(');
-  if (c)
-    {
-      while(c-->s)
-	if (*c == '.')
-	  break;
-
-      if (*c == '.')
-	{
-	  *c = 0;
-	  class_name = s;
-	  method_name = c+1;
-	}
-      else
-	{
-	  class_name = NULL;
-	  method_name = s;
-	}
-    }
-  else
-    {
-      class_name = NULL;
-      method_name = s;
-    }
-
-  // Get line number
-  int line_number;
-  c = strrchr (f, ':');
-  if (c)
-    {
-      if (c[1] != 0)
-	line_number = atoi(c+1);
-      else
-	line_number = -1;
-      *c = 0;
-    }
-  else
-    {
-      line_number = -1;
-      c = strchr (f, '\n');
-      if (c)
-	*c = 0;
-    }
-
- fail:
-  return new java::lang::StackTraceElement(
-		  f ? JvNewStringLatin1 (f) : NULL,
-		  line_number,
-		  class_name ? JvNewStringLatin1 (class_name) : NULL,
-		  JvNewStringLatin1 (method_name ? method_name : s),
-		  false);
-}
-
-/* Given a pointer to a function or method, try to convert it into a
-   name and the appropriate line and source file.  The caller passes
-   the code pointer in p.
-
-   Returns false if the lookup fails.  Even if this happens, the field
-   he will have been correctly filled in with the pointer.  */
-
-java::lang::StackTraceElement*
-_Jv_name_finder::lookup (void *p)
-{
-  extern char **_Jv_argv;
-  toHex (p);
-      
-  char name[1024];
-  char file_name[1024];
-
-  file_name[0] = 0;
-
-#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
-  {
-    Dl_info dl_info;
-    
-    if (dladdr (p, &dl_info))
-      {
-        if (dl_info.dli_fname)
-	  strncpy (file_name, dl_info.dli_fname, sizeof file_name);
-	if (dl_info.dli_sname)
-	  strncpy (name, dl_info.dli_sname, sizeof name);
-       
-       /* Don't trust dladdr() if the address is from the main program. */
-       if (dl_info.dli_fname != NULL
-           && dl_info.dli_sname != NULL
-	   && (_Jv_argv == NULL || strcmp (file_name, _Jv_argv[0]) != 0))
-         return createStackTraceElement (name, file_name);
-      }
-  }
-#endif
-
-  memcpy (name, hex, strlen (hex) + 1);
-
-#if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
-  if (lookup_error)
-    goto fail;
-
-  lookup_error |= write (f_pipe[1], hex, strlen (hex)) < 0;
-  if (lookup_error)
-    goto fail;
-  lookup_error |= write (f_pipe[1], "\n", 1) < 0;
-  if (lookup_error)
-    goto fail;
-
-  lookup_error |= (fgets (name, sizeof name, b_pipe_fd) == NULL);
-  if (lookup_error)
-    goto fail;
-  lookup_error |= (fgets (file_name, sizeof file_name, b_pipe_fd) == NULL);
-  if (lookup_error)
-    goto fail;
-
-  {
-    char *newline = strchr (name, '\n');
-    if (newline)
-      *newline = 0;
-  }
-#endif /* defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) */
-
- fail:
-  return (createStackTraceElement (name, file_name));
-}
Index: gcj/javaprims.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/javaprims.h,v
retrieving revision 1.40
diff -u -r1.40 javaprims.h
--- gcj/javaprims.h	12 Jul 2002 12:52:43 -0000	1.40
+++ gcj/javaprims.h	26 Jul 2002 20:37:24 -0000
@@ -211,6 +211,7 @@
       class UnsupportedOperationException;
       class VMClassLoader;
       class VMSecurityManager;
+      class VMThrowable;
       class VerifyError;
       class VirtualMachineError;
       class Void;
Index: gnu/gcj/runtime/NameFinder.java
===================================================================
RCS file: gnu/gcj/runtime/NameFinder.java
diff -N gnu/gcj/runtime/NameFinder.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/gcj/runtime/NameFinder.java	26 Jul 2002 20:37:24 -0000
@@ -0,0 +1,375 @@
+/* NameFinder.java -- Translates addresses to StackTraceElements.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+
+   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.runtime;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.File;
+import java.io.PrintWriter;
+
+/**
+ * Helper class that translates addresses (represented as longs) to a
+ * StackTraceElement array.
+ *
+ * There are a couple of system properties that can be set to manipulate the
+ * result (all default to true):
+ * <li>
+ * <ul><code>gnu.gcj.runtime.NameFinder.demangle</code>
+ *     Whether names should be demangled.</ul>
+ * <ul><code>gnu.gcj.runtime.NameFinder.sanitize</code></ul>
+ *     Whether calls to initialize exceptions and starting the runtime system
+ *     should be removed from the stack trace. Only done when names are
+ *     demangled.</ul>
+ * <ul><code>gnu.gcj.runtime.NameFinder.remove_unknown</code>
+ *     Wheter calls to unknown functions (class and method names are unknown)
+ *     should be removed from the stack trace. Only done when the stack is
+ *     sanitized.</ul>
+ * <ul><code>gnu.gcj.runtime.NameFinder.use_addr2line</code>
+ *     Wheter an external process (addr2line) should be used as fallback to
+ *     convert the addresses to function names when the runtime is unable to
+ *     do it through <code>dladdr</code>.</ul>
+ * </li>
+ *
+ * <code>close()</code> should be called to get rid of all resources.
+ *
+ * This class is used from <code>java.lang.VMThrowable</code>.
+ *
+ * Currently the <code>lookup(long[])</code> method is not thread safe.
+ * It can easily be made thread safe by synchronizing access to all external
+ * processes when used.
+ *   
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class NameFinder
+{
+  // Set these to false when not needed.
+  private static final boolean demangle
+	  = Boolean.valueOf(System.getProperty
+		("gnu.gcj.runtime.NameFinder.demangle", "true")
+	    ).booleanValue();
+  private static final boolean sanitize
+	  = Boolean.valueOf(System.getProperty
+		("gnu.gcj.runtime.NameFinder.sanitize", "true")
+	    ).booleanValue();
+  private static final boolean remove_unknown
+	  = Boolean.valueOf(System.getProperty
+		("gnu.gcj.runtime.NameFinder.remove_unknown", "true")
+	    ).booleanValue();
+  private static final boolean use_addr2line
+	  = Boolean.valueOf(System.getProperty
+		("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
+	    ).booleanValue();
+
+  /**
+   * The name of the currently running executable.
+   */
+  private final String executable;
+
+  /**
+   * Process used for demangling names.
+   */
+  private Process cppfilt;
+
+  private PrintWriter cppfiltOut;
+  private BufferedReader cppfiltIn;
+
+  /**
+   * Process used for translating addresses to function/file names.
+   */
+  private Process addr2line;
+
+  private PrintWriter addr2lineOut;
+  private BufferedReader addr2lineIn;
+
+  /**
+   * Creates a new NameFinder. Call close to get rid of any resources
+   * created while using the <code>lookup</code> methods.
+   */
+  public NameFinder()
+  {
+    executable = getExecutable();
+    Runtime runtime = Runtime.getRuntime();
+    if (demangle)
+    {
+      try
+	{
+	  String[] exec = new String[] {"c++filt", "-s", "java"};
+	  cppfilt = runtime.exec(exec);
+	  cppfiltIn = new BufferedReader
+			(new InputStreamReader(cppfilt.getInputStream()));
+	  cppfiltOut = new PrintWriter(cppfilt.getOutputStream());
+	}
+      catch (IOException ioe)
+        {
+	  if (cppfilt != null)
+	    cppfilt.destroy();
+	  cppfilt = null;
+	}
+    }
+
+    if (use_addr2line)
+      {
+	try
+	  {
+	    String[] exec = new String[] {"addr2line", "-f", "-e", executable};
+	    addr2line = runtime.exec(exec);
+	  }
+	catch (IOException ioe)
+	  {
+	    try
+	      {
+		String[] exec = new String[] {"addr2line.awk", executable};
+		addr2line = runtime.exec(exec);
+	      }
+	    catch (IOException ioe2) { addr2line = null; }
+	  }
+
+	if (addr2line != null)
+	  {
+	    try
+	      {
+		addr2lineIn = new BufferedReader
+			(new InputStreamReader(addr2line.getInputStream()));
+		addr2lineOut = new PrintWriter(addr2line.getOutputStream());
+	      }
+	    catch (IOException ioe)
+	      {  
+		addr2line.destroy();
+		addr2line = null;
+	      }
+	  }
+      }
+  }
+
+  /**
+   * Returns the name of the currently running process.
+   */
+  native private static String getExecutable();
+
+  /**
+   * Tries to use dladdr to create a StackTraceElement from the given address.
+   * Returns null on failure.
+   */
+  native private StackTraceElement dladdrLookup(long addr);
+
+  private StackTraceElement lookup(long addr)
+  {
+    StackTraceElement result;
+
+    result = dladdrLookup(addr);
+    if (result == null)
+      {
+	String hex = "0x"+Long.toHexString(addr);
+	if (addr2line != null)
+	  {
+	    try
+	      {
+		addr2lineOut.println(hex);
+		addr2lineOut.flush();
+		String name = addr2lineIn.readLine();
+		String file = addr2lineIn.readLine();
+		if ("??".equals(name))
+		  name = hex;
+		result = createStackTraceElement(name, file);
+	      }
+	    catch (IOException ioe) { addr2line = null; }
+	  }
+
+	if (result == null)
+	  result = new StackTraceElement(null, -1, null, hex, false);
+      }
+
+    return result;
+  }
+
+  /**
+   * Given an Throwable and a array of longs representing addresses
+   * returns an array of StackTraceElement containing class, method, file
+   * and linenumbers.
+   */
+  public StackTraceElement[] lookup(Throwable t, long addrs[])
+  {
+    int length = addrs.length;
+    StackTraceElement[] elements = new StackTraceElement[length];
+    for (int i=0; i < length; i++)
+      elements[i] = lookup(addrs[i]);
+
+    if (demangle && sanitize)
+      return sanitizeStack(elements, t);
+    else
+      return elements;
+  }
+
+  final static String main = "main(java.lang.String[])";
+  /**
+   * Removes calls to initialize exceptions and the runtime system from
+   * the stack trace including stack frames of which nothing usefull is known.
+   * Throw away the top of the stack till we find the constructor(s)
+   * of this Throwable or at least the contructors of java.lang.Throwable.
+   * Also throw away from the top everything before a runtime _Jv_Throw call.
+   */
+  private static StackTraceElement[] sanitizeStack(StackTraceElement[] elements,
+						   Throwable t)
+  {
+    StackTraceElement[] stack;
+
+    String className = t.getClass().getName();
+    String consName;
+    int lastDot = className.lastIndexOf('.');
+    if (lastDot == -1)
+      consName = className + '(';
+    else
+      consName = className.substring(lastDot + 1) + '(';
+
+    int unknown = 0;
+    int last_throw = -1;
+    int length = elements.length;
+    int end = length-1;
+    for (int i = 0; i < length; i++)
+      {
+	String CName = elements[i].getClassName();
+	String MName = elements[i].getMethodName();
+	if ((CName == null && MName != null && MName.startsWith("_Jv_Throw"))
+	  ||
+	   (CName != null
+	    && (CName.equals(className) || CName.equals("java.lang.Throwable"))
+	    && MName != null
+	    && (MName.startsWith(consName) || MName.startsWith("Throwable("))))
+	  last_throw = i;
+	else if (remove_unknown && CName == null 
+		 && (MName == null || MName.startsWith("0x")))
+	  unknown++;
+	else if (main.equals(MName))
+	  {
+	    end = i;
+	    break;
+	  }
+      }
+    int begin = last_throw+1;
+
+    if (begin > 0 || end < length-1 || unknown > 0)
+      {
+	stack = new StackTraceElement[end-begin-unknown+1];
+	int pos =0;
+	for (int i=begin; i<=end; i++)
+	  {
+	    String MName;
+	    if (unknown == 0
+		|| !(elements[i].getClassName() == null
+		     && ((MName = elements[i].getMethodName()) == null
+			 || MName.startsWith("0x"))))
+	      {
+		stack[pos] = elements[i];
+		pos++;
+	      }
+	  }
+      }
+    else
+      stack = elements;
+
+    return stack;
+  }
+
+  /**
+   * Creates a StackTraceElement given a string and a filename.
+   * Splits the given string into the class and method part.
+   * The string name will be a demangled to a fully qualified java method
+   * string. The string file will be decomposed into a file name and possibly
+   * a line number.
+   */
+  private StackTraceElement createStackTraceElement(String name, String file)
+  {
+    if (!demangle)
+      return new StackTraceElement(file, -1, null, name, false);
+
+    String s = demangleName(name);
+    String methodName = s;
+    String className = null;
+    int bracket = s.indexOf('(');
+    if (bracket > 0)
+      {
+	int dot = s.lastIndexOf('.', bracket);
+	if (dot > 0)
+	  {
+	    className = s.substring(0, dot);
+	    methodName = s.substring(dot+1, s.length());
+	  }
+      }
+
+    String fileName = file;
+    int line = -1;
+    if (fileName != null)
+      {
+	int colon = file.indexOf(':');
+	if (colon > 0)
+	  {
+	    fileName = file.substring(0, colon);
+	    try
+	      {
+		line = Integer.parseInt(file.substring(colon+1, file.length()));
+	      }
+	    catch (NumberFormatException nfe) { /* ignore */ }
+	  }
+
+	if (line == 0)
+	  line =-1;
+
+	if ("??".equals(fileName))
+	  fileName = null;
+	else
+	  {
+	    try
+	      {
+		fileName = new File(fileName).getCanonicalPath();
+	      }
+	    catch (IOException ioe) { /* ignore */ }
+	  }
+      }
+
+    return new StackTraceElement(fileName, line, className, methodName, false);
+  }
+
+  private String demangleName(String s)
+  {
+    if (cppfilt != null)
+    {
+      try
+	{
+	  cppfiltOut.println(s);
+	  cppfiltOut.flush();
+	  return cppfiltIn.readLine();
+	}
+      catch (IOException ioe) { cppfilt.destroy(); cppfilt = null; }
+    }
+
+    return s;
+  }
+
+  /**
+   * Releases all resources used by this NameFinder.
+   */
+  public void close()
+  {
+    if (cppfilt != null)
+      cppfilt.destroy();
+
+    if (addr2line != null)
+      addr2line.destroy();
+  }
+
+  /**
+   * Calls close to get rid of all resources.
+   */
+  protected void finalize()
+  {
+    close();
+  }
+}
Index: gnu/gcj/runtime/natNameFinder.cc
===================================================================
RCS file: gnu/gcj/runtime/natNameFinder.cc
diff -N gnu/gcj/runtime/natNameFinder.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/gcj/runtime/natNameFinder.cc	26 Jul 2002 20:37:24 -0000
@@ -0,0 +1,61 @@
+// natNameFinder.cc - native helper methods for NameFiner.java
+
+/* Copyright (C) 2002  Free Software Foundation, Inc
+
+   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.  */
+
+/**
+ * @author Mark Wielaard (mark@klomp.org)
+ * Based on the old name-finder.cc by Andrew Haley <aph@cygnus.com>.
+ */
+
+#include <config.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+#include <java/lang/String.h>
+#include <java/lang/StackTraceElement.h>
+
+#include <gnu/gcj/runtime/NameFinder.h>
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+java::lang::String*
+gnu::gcj::runtime::NameFinder::getExecutable (void)
+{
+    return JvNewStringLatin1 (_Jv_ThisExecutable ());
+}
+
+java::lang::StackTraceElement*
+gnu::gcj::runtime::NameFinder::dladdrLookup(jlong addr)
+{
+#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
+  extern char **_Jv_argv;
+  char name[1024];
+  char file_name[1024];
+  void* p = (void*) (long) addr;
+  Dl_info dl_info;
+   
+  if (dladdr (p, &dl_info))
+    {
+      if (dl_info.dli_fname)
+        strncpy (file_name, dl_info.dli_fname, sizeof file_name);
+      if (dl_info.dli_sname)
+        strncpy (name, dl_info.dli_sname, sizeof name);
+     
+     /* Don't trust dladdr() if the address is from the main program. */
+     if (dl_info.dli_fname != NULL
+         && dl_info.dli_sname != NULL
+         && (_Jv_argv == NULL || strcmp (file_name, _Jv_argv[0]) != 0))
+       return createStackTraceElement (JvNewStringLatin1 (name),
+				       JvNewStringLatin1 (file_name));
+    }
+#endif
+  return NULL;
+}
Index: include/name-finder.h
===================================================================
RCS file: include/name-finder.h
diff -N include/name-finder.h
--- include/name-finder.h	12 Jul 2002 12:52:44 -0000	1.7
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,103 +0,0 @@
-// name-finder.h - Convert addresses to names
-
-/* Copyright (C) 2000, 2002  Free Software Foundation, Inc
-
-   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.  */
-
-/**
- * @author Andrew Haley <aph@cygnus.com>
- * @date Jan 6  2000
- */
-
-#include <gcj/cni.h>
-#include <jvm.h>
-
-#include <sys/types.h>
-
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#include <string.h>
-#include <stdio.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include <java/lang/StackTraceElement.h>
-
-/* _Jv_name_finder is a class wrapper around a mechanism that can
-   convert addresses of methods to their names and the names of files
-   in which they appear. */
-
-class _Jv_name_finder
-{
-public:  
-  _Jv_name_finder (char *executable);
-  ~_Jv_name_finder ()
-    {
-#if defined (HAVE_PIPE) && defined (HAVE_FORK)
-      myclose (f_pipe[0]);
-      myclose (f_pipe[1]);
-      myclose (b_pipe[0]);
-      myclose (b_pipe[1]);
-      if (b_pipe_fd != NULL)
-	fclose (b_pipe_fd);
-
-      myclose (f2_pipe[0]);
-      myclose (f2_pipe[1]);
-      myclose (b2_pipe[0]);
-      myclose (b2_pipe[1]);
-      if (b2_pipe_fd != NULL)
-	fclose (b2_pipe_fd);
-
-      if (pid >= 0)
-	{
-	  int wstat;
-	  // We don't care about errors here.
-	  waitpid (pid, &wstat, 0);
-	}
-
-      if (pid2 >= 0)
-	{
-	  int wstat;
-	  // We don't care about errors here.
-	  waitpid (pid2, &wstat, 0);
-	}
-#endif
-    }
-
-/* Given a pointer to a function or method, try to convert it into a
-   name and the appropriate line and source file.  The caller passes
-   the code pointer in p.
-
-   Returns NULL if the lookup fails.  Even if this happens, the field
-   hex will have been correctly filled in with the pointer. */
-
-  java::lang::StackTraceElement* lookup (void *p);
-
-  char hex[sizeof (void *) * 2 + 5];
-
-private:
-  void toHex (void *p);
-  java::lang::StackTraceElement* createStackTraceElement(char *s, char *f);
-#if defined (HAVE_PIPE) && defined (HAVE_FORK)
-  pid_t pid, pid2;
-  int f_pipe[2], b_pipe[2], f2_pipe[2], b2_pipe[2];
-  FILE *b_pipe_fd, *b2_pipe_fd;
-  int demangling_error, lookup_error;
-
-  // Close a descriptor only if it has not been closed.
-  void myclose (int fd)
-  {
-    if (fd != -1)
-      close (fd);
-  }
-
-#endif
-};
Index: java/lang/Throwable.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Throwable.java,v
retrieving revision 1.12
diff -u -r1.12 Throwable.java
--- java/lang/Throwable.java	12 Jul 2002 12:52:44 -0000	1.12
+++ java/lang/Throwable.java	26 Jul 2002 20:37:25 -0000
@@ -46,11 +46,6 @@
 import java.io.IOException;
 import java.io.OutputStream;
 
-/**
- * @author Tom Tromey <tromey@cygnus.com>
- * @date October 30, 1998 
- */
-
 /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
  * "The Java Language Specification", ISBN 0-201-63451-1
  * Status: Sufficient for compiled code, but methods applicable to
@@ -116,7 +111,7 @@
  * @author Tom Tromey
  * @author Eric Blake <ebb9@email.byu.edu>
  * @since 1.0
- * @status still missing 1.4 functionality
+ * @status updated to 1.4
  */
 public class Throwable implements Serializable
 {
@@ -130,7 +125,7 @@
    *
    * @serial specific details about the exception, may be null
    */
-  private String detailMessage;
+  private final String detailMessage;
 
   /**
    * The cause of the throwable, including null for an unknown or non-chained
@@ -374,7 +369,7 @@
    */
   public void printStackTrace(PrintStream s)
   {
-    printStackTrace(new PrintWriter(s));
+    s.print(stackTraceString());
   }
 
   /**
@@ -409,72 +404,88 @@
    */
   public void printStackTrace (PrintWriter pw)
   {
-    // First line
-    pw.println(toString());
+    pw.print(stackTraceString());
+  }
 
-    // The stacktrace
+  private static final String nl = System.getProperty("line.separator");
+  // Create whole stack trace in a stringbuffer so we don't have to print
+  // it line by line. This prevents printing multiple stack traces from
+  // different threads to get mixed up when written to the same PrintWriter.
+  private String stackTraceString()
+  {
+    StringBuffer sb = new StringBuffer();
+
+    // Main stacktrace
     StackTraceElement[] stack = getStackTrace();
-    if (stack == null || stack.length == 0)
-      {
-	pw.println("   <<No stacktrace available>>");
-	return;
-      }
-    else
-      {
-	for (int i = 0; i < stack.length; i++)
-	  pw.println("   at " + stack[i]);
-      }
+    stackTraceStringBuffer(sb, this.toString(), stack, 0);
 
     // The cause(s)
     Throwable cause = getCause();
     while (cause != null)
       {
-        // Cause first line
-        pw.println("Caused by: " + cause);
+	// Cause start first line
+        sb.append("Caused by: ");
 
         // Cause stacktrace
         StackTraceElement[] parentStack = stack;
         stack = cause.getStackTrace();
-	if (stack == null || stack.length == 0)
-	  {
-	    pw.println("   <<No stacktrace available>>");
-	  }
-	else if (parentStack == null || parentStack.length == 0)
-	  {
-	    for (int i = 0; i < stack.length; i++)
-	      pw.println("   at " + stack[i]);
-	  }
+	if (parentStack == null || parentStack.length == 0)
+	  stackTraceStringBuffer(sb, cause.toString(), stack, 0);
 	else
 	  {
-	    boolean equal = false; // Is rest of stack equal to parent frame?
-	    for (int i = 0; i < stack.length && ! equal; i++)
+	    int equal = 0; // Count how many of the last stack frames are equal
+	    int frame = stack.length-1;
+	    int parentFrame = parentStack.length-1;
+	    while (frame > 0 && parentFrame > 0)
 	      {
-		// Check if we already printed the rest of the stack
-		// since it was the tail of the parent stack
-		int remaining = stack.length - i;
-		int element = i;
-		int parentElement = parentStack.length - remaining;
-		equal = parentElement >= 0
-		      && parentElement < parentStack.length; // be optimistic
-		while (equal && element < stack.length)
+		if (stack[frame].equals(parentStack[parentFrame]))
 		  {
-		    if (stack[element].equals(parentStack[parentElement]))
-		      {
-			element++;
-			parentElement++;
-		      }
-		    else
-		      equal = false;
+		    equal++;
+		    frame--;
+		    parentFrame--;
 		  }
-		// Print stacktrace element or indicate the rest is equal 
-		if (! equal)
-		  pw.println("   at " + stack[i]);
 		else
-		  pw.println("   ..." + remaining + " more");
+		  break;
 	      }
+	    stackTraceStringBuffer(sb, cause.toString(), stack, equal);
 	  }
         cause = cause.getCause();
       }
+
+    return sb.toString();
+  }
+
+  // Adds to the given StringBuffer a line containing the name and
+  // all stacktrace elements minus the last equal ones.
+  private static void stackTraceStringBuffer(StringBuffer sb, String name,
+					StackTraceElement[] stack, int equal)
+  {
+    // (finish) first line
+    sb.append(name);
+    sb.append(nl);
+
+    // The stacktrace
+    if (stack == null || stack.length == 0)
+      {
+	sb.append("   <<No stacktrace available>>");
+	sb.append(nl);
+      }
+    else
+      {
+	for (int i = 0; i < stack.length-equal; i++)
+	  {
+	    sb.append("   at ");
+	    sb.append(stack[i] == null ? "<<Unknown>>" : stack[i].toString());
+	    sb.append(nl);
+	  }
+	if (equal > 0)
+	  {
+	    sb.append("   ...");
+	    sb.append(equal);
+	    sb.append(" more");
+	    sb.append(nl);
+	  }
+      }
   }
 
   /**
@@ -483,7 +494,13 @@
    * @return this same throwable
    * @see #printStackTrace()
    */
-  public native Throwable fillInStackTrace();
+  public Throwable fillInStackTrace()
+  {
+    vmState = VMThrowable.fillInStackTrace(this);
+    stackTrace = null; // Should be regenerated when used.
+
+    return this;
+  }
 
   /**
    * Provides access to the information printed in {@link #printStackTrace()}.
@@ -499,7 +516,13 @@
   public StackTraceElement[] getStackTrace()
   {
     if (stackTrace == null)
-      stackTrace = getStackTrace0();
+      if (vmState == null)
+	stackTrace = new StackTraceElement[0];
+      else 
+	{
+	  stackTrace = vmState.getStackTrace(this);
+	  vmState = null; // No longer needed
+	}
 
     return stackTrace;
   }
@@ -515,15 +538,17 @@
    */
   public void setStackTrace(StackTraceElement[] stackTrace)
   {
+    // XXX - should we copy/clone the StackTraceElements to prevent tempering?
     for (int i = stackTrace.length; --i >= 0; )
       if (stackTrace[i] == null)
         throw new NullPointerException();
     this.stackTrace = stackTrace;
   }
 
-  private native final StackTraceElement[] getStackTrace0 ();
-
-  // Setting this flag to false prevents fillInStackTrace() from running.
-  static boolean trace_enabled = true;
-  private transient byte stackTraceBytes[];
+  /**
+   * VM state when fillInStackTrace was called.
+   * Used by getStackTrace() to get an array of StackTraceElements.
+   * Cleared when no longer needed.
+   */
+  private transient VMThrowable vmState;
 }
Index: java/lang/VMThrowable.java
===================================================================
RCS file: java/lang/VMThrowable.java
diff -N java/lang/VMThrowable.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ java/lang/VMThrowable.java	26 Jul 2002 20:37:25 -0000
@@ -0,0 +1,89 @@
+/* java.lang.VMThrowable -- VM support methods for Throwable.
+   Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.lang;
+
+import gnu.gcj.runtime.NameFinder;
+
+/**
+ * VM dependant state and support methods Throwabele.
+ * It is deliberately package local and final and should only be accessed
+ * by the Throwable class.
+ * <p>
+ * This is the version used by libgcj (http://gcc.gnu.org/java/).
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+final class VMThrowable
+{
+  private long stackTraceAddrs[];
+
+  /**
+   * Private contructor, create VMThrowables with fillInStackTrace();
+   */
+  private VMThrowable() { }
+
+  /**
+   * Fill in the stack trace with the current execution stack.
+   * Called by <code>Throwable.fillInStackTrace()</code> to get the state of
+   * the VM. Can return null when the VM does not support caputing the VM
+   * execution state.
+   *
+   * @return a new VMThrowable containing the current execution stack trace.
+   * @see Throwable#fillInStackTrace()
+   */
+  static native VMThrowable fillInStackTrace(Throwable t);
+
+  /**
+   * Returns an <code>StackTraceElement</code> array based on the execution
+   * state of the VM as captured by <code>fillInStackTrace</code>.
+   * Called by <code>Throwable.getStackTrace()</code>.
+   *
+   * @return a non-null but possible zero length array of StackTraceElement.
+   * @see Throwable#getStackTrace()
+   */
+  StackTraceElement[] getStackTrace(Throwable t)
+  {
+    NameFinder nameFinder = new NameFinder();
+    StackTraceElement[] result = nameFinder.lookup(t, stackTraceAddrs);
+    nameFinder.close();
+    return result;
+  }
+
+  // Setting this flag to false prevents fillInStackTrace() from running.
+  static boolean trace_enabled = true;
+}
Index: java/lang/natThrowable.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natThrowable.cc,v
retrieving revision 1.13
diff -u -r1.13 natThrowable.cc
--- java/lang/natThrowable.cc	12 Jul 2002 12:52:44 -0000	1.13
+++ java/lang/natThrowable.cc	26 Jul 2002 20:37:25 -0000
@@ -1,6 +1,6 @@
 // natThrowable.cc - Superclass for all exceptions.
 
-/* Copyright (C) 2000  Free Software Foundation, Inc
+/* Copyright (C) 2000, 2002  Free Software Foundation, Inc
 
    This file is part of libgcj.
 
@@ -11,6 +11,9 @@
 /**
  * @author Andrew Haley <aph@cygnus.com>
  * @date Jan 6  2000
+ *
+ * All VM specific methods are now implemented by VMThrowable, but this file
+ * is still called natThrowable.cc.
  */
 
 #include <config.h>
@@ -22,15 +25,11 @@
 #include <java/lang/Object.h>
 #include <java-threads.h>
 #include <java/lang/Throwable.h>
-#include <java/lang/StackTraceElement.h>
-#include <java/io/PrintStream.h>
-#include <java/io/PrintWriter.h>
-#include <java/io/IOException.h>
+#include <java/lang/VMThrowable.h>
 
 #include <sys/types.h>
 
 #include <stdlib.h>
-#include <stdio.h>
 
 #include <unistd.h>
 
@@ -38,62 +37,29 @@
 #include <execinfo.h>
 #endif
 
-#include <name-finder.h>
-
 /* FIXME: size of the stack trace is limited to 128 elements.  It's
    undoubtedly sensible to limit the stack trace, but 128 is rather
    arbitrary.  It may be better to configure this.  */
 
-java::lang::Throwable *
-java::lang::Throwable::fillInStackTrace (void)
+java::lang::VMThrowable *
+java::lang::VMThrowable::fillInStackTrace (java::lang::Throwable* t)
 {
   if (! trace_enabled)
-    return this;
+    return NULL;
 #if defined (HAVE_BACKTRACE)
+  VMThrowable* state = new VMThrowable;
   void *p[128];
   
   // We subtract 1 from the number of elements because we don't want
-  // to include the call to fillInStackTrace in the trace.
+  // to include the calls to fillInStackTrace in the trace.
   int n = backtrace (p, 128) - 1;  
 
-  if (n > 0)
-    {
-      // We copy the array below to deal with alignment issues.
-      stackTraceBytes = JvNewByteArray (n * sizeof p[0]);
-      memcpy (elements (stackTraceBytes), p+1, (n * sizeof p[0]));
-    }
+  state->stackTraceAddrs = JvNewLongArray (n);
+  jlong *addrs = elements (state->stackTraceAddrs);
+  while (n--)
+    addrs[n] = (long)p[n];
 
+  return state;
 #endif
-
-  return this;
-}
-
-JArray<java::lang::StackTraceElement*> *
-java::lang::Throwable::getStackTrace0 ()
-{
-#ifdef HAVE_BACKTRACE
-  if (!stackTraceBytes)
-    return NULL;
-
-  int depth = stackTraceBytes->length / sizeof (void *);
-  void *p[depth];
-  // This memcpy is esential; it ensures that the array of void* is
-  // correctly aligned.
-  memcpy (p, elements (stackTraceBytes), sizeof p);
-
-  JArray<java::lang::StackTraceElement*> *result;
-  java::lang::StackTraceElement** el;
-  result = reinterpret_cast <JArray<java::lang::StackTraceElement *>*>
-    (JvNewObjectArray (depth, &java::lang::StackTraceElement::class$, NULL));
-  el = elements (result);
-
-  _Jv_name_finder finder (_Jv_ThisExecutable ());
-
-  for (int i = 0; i < depth; i++)
-    el[i] = finder.lookup (p[i]);
-
-  return result;
-#else
   return NULL;
-#endif /* HAVE_BACKTRACE */
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]