This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Re: StackTraceElement support
Thanks for the patch.
A niggle:
Your patch isn't as robust as the previous code in that it now fails
to produce any useful output if addr2line or c++filt are absent.
These executables aren't always present, and it's important to produce
some sort of stack trace if at all possible. I hacked your patch
about a bit to re-introduce that robustness.
See what you think -- if you agree with what I've done, please check
it in.
Andrew.
FYI: I'm thinking of getting rid of the call to c++filt altogether --
it's not needed because addr2line will work on shared objects and can
now produce Java demangling. That gets us line numbers in shared
objects too. Bonus...
2002-07-06 Mark Wielaard <mark@klomp.org>
* java/lang/natThrowable.cc (printRawStackTrace): removed.
(getStackTrace0): new method.
* java/lang/Throwable.java (CPlusPlusDemangler): removed.
(printStackTrace(PrintWriter)): replace with pure java implementation.
(printRawStackTrace): removed.
(getStackTrace0): new method.
* gcj/javaprims.h: regenerate class list.
* include/name-finder.h (lookup): returns StackTraceElement*.
(method_name, file_name): fields removed.
(pid2, f2_pipe, b2_pipe, b2_pipe_fd): new fields.
(~_Jv_name_finder): close new descriptors.
* name-finder.cc(_Jv_name_finder): setup c++filt helper process.
(createStackTraceElement): new method.
(lookup): returns StackTraceElement*, uses createStackTraceElement().
Index: libjava/name-finder.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/name-finder.cc,v
retrieving revision 1.11
diff -c -2 -p -r1.11 name-finder.cc
*** libjava/name-finder.cc 23 Mar 2002 16:14:27 -0000 1.11
--- libjava/name-finder.cc 11 Jul 2002 17:37:19 -0000
*************** _Jv_name_finder::_Jv_name_finder (char *
*** 60,64 ****
{
#if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
! error = 0;
// Initialize file descriptors so that shutdown works properly.
--- 60,64 ----
{
#if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
! demangling_error = lookup_error = 0;
// Initialize file descriptors so that shutdown works properly.
*************** _Jv_name_finder::_Jv_name_finder (char *
*** 69,73 ****
b_pipe_fd = NULL;
! char *argv[6];
{
int arg = 0;
--- 69,81 ----
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;
*************** _Jv_name_finder::_Jv_name_finder (char *
*** 76,80 ****
#else
argv[arg++] = "addr2line";
- argv[arg++] = "-C";
argv[arg++] = "-f";
argv[arg++] = "-e";
--- 84,87 ----
*************** _Jv_name_finder::_Jv_name_finder (char *
*** 84,91 ****
}
! error |= pipe (f_pipe) < 0;
! error |= pipe (b_pipe) < 0;
! if (error)
return;
--- 91,98 ----
}
! lookup_error |= pipe (f_pipe) < 0;
! lookup_error |= pipe (b_pipe) < 0;
! if (lookup_error)
return;
*************** _Jv_name_finder::_Jv_name_finder (char *
*** 110,125 ****
if (pid < 0)
{
! error |= 1;
return;
}
b_pipe_fd = fdopen (b_pipe[0], "r");
! error |= !b_pipe_fd;
! if (! error)
{
// Don't try to close the fd twice.
b_pipe[0] = -1;
}
#endif
}
--- 117,179 ----
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
}
*************** _Jv_name_finder::toHex (void *p)
*** 145,148 ****
--- 199,290 ----
}
+ /* 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
*************** _Jv_name_finder::toHex (void *p)
*** 152,156 ****
he will have been correctly filled in with the pointer. */
! bool
_Jv_name_finder::lookup (void *p)
{
--- 294,298 ----
he will have been correctly filled in with the pointer. */
! java::lang::StackTraceElement*
_Jv_name_finder::lookup (void *p)
{
*************** _Jv_name_finder::lookup (void *p)
*** 158,161 ****
--- 300,308 ----
toHex (p);
+ char name[1024];
+ char file_name[1024];
+
+ file_name[0] = 0;
+
#if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
{
*************** _Jv_name_finder::lookup (void *p)
*** 167,171 ****
strncpy (file_name, dl_info.dli_fname, sizeof file_name);
if (dl_info.dli_sname)
! strncpy (method_name, dl_info.dli_sname, sizeof method_name);
/* Don't trust dladdr() if the address is from the main program. */
--- 314,318 ----
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. */
*************** _Jv_name_finder::lookup (void *p)
*** 173,210 ****
&& dl_info.dli_sname != NULL
&& (_Jv_argv == NULL || strcmp (file_name, _Jv_argv[0]) != 0))
! return true;
}
}
#endif
! #if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
! if (error)
! return false;
! error |= write (f_pipe[1], hex, strlen (hex)) < 0;
! if (error)
! return false;
! error |= write (f_pipe[1], "\n", 1) < 0;
! if (error)
! return false;
!
! error |= (fgets (method_name, sizeof method_name, b_pipe_fd) == NULL);
! if (error)
! return false;
! error |= (fgets (file_name, sizeof file_name, b_pipe_fd) == NULL);
! if (error)
! return false;
!
! char *newline = strchr (method_name, '\n');
! if (newline)
! *newline = 0;
! newline = strchr (file_name, '\n');
! if (newline)
! *newline = 0;
! return true;
! #else
! return false;
#endif /* defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) */
}
--- 320,356 ----
&& 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: libjava/gcj/javaprims.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gcj/javaprims.h,v
retrieving revision 1.39
diff -c -2 -p -r1.39 javaprims.h
*** libjava/gcj/javaprims.h 18 Jun 2002 17:06:42 -0000 1.39
--- libjava/gcj/javaprims.h 11 Jul 2002 17:37:19 -0000
*************** extern "Java"
*** 135,139 ****
class Boolean;
class Byte;
- class CPlusPlusDemangler;
class CharSequence;
class Character;
--- 135,138 ----
*************** extern "Java"
*** 365,368 ****
--- 364,371 ----
class JarOutputStream;
class Manifest;
+ };
+
+ namespace regex
+ {
};
Index: libjava/include/name-finder.h
===================================================================
RCS file: /cvs/gcc/gcc/libjava/include/name-finder.h,v
retrieving revision 1.6
diff -c -2 -p -r1.6 name-finder.h
*** libjava/include/name-finder.h 23 Mar 2002 16:14:28 -0000 1.6
--- libjava/include/name-finder.h 11 Jul 2002 17:37:19 -0000
*************** details. */
*** 30,33 ****
--- 30,35 ----
#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
*************** public:
*** 48,51 ****
--- 50,60 ----
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)
{
*************** public:
*** 54,57 ****
--- 63,73 ----
waitpid (pid, &wstat, 0);
}
+
+ if (pid2 >= 0)
+ {
+ int wstat;
+ // We don't care about errors here.
+ waitpid (pid2, &wstat, 0);
+ }
#endif
}
*************** public:
*** 61,83 ****
the code pointer in p.
! Returns false if the lookup fails. Even if this happens, the field
! hex will have been correctly filled in with the pointer.
! The other fields are method_name and file_name, which lookup will
! attempt to fill appropriately. If the lookup has failed, these
! fields contain garbage.*/
! bool lookup (void *p);
- char method_name[1024];
- char file_name[1024];
char hex[sizeof (void *) * 2 + 5];
private:
void toHex (void *p);
#if defined (HAVE_PIPE) && defined (HAVE_FORK)
! pid_t pid;
! int f_pipe[2], b_pipe[2];
! FILE *b_pipe_fd;
! int error;
// Close a descriptor only if it has not been closed.
--- 77,95 ----
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.
Index: libjava/java/lang/StackTraceElement.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/StackTraceElement.java,v
retrieving revision 1.1
diff -c -2 -p -r1.1 StackTraceElement.java
*** libjava/java/lang/StackTraceElement.java 24 May 2002 10:40:43 -0000 1.1
--- libjava/java/lang/StackTraceElement.java 11 Jul 2002 17:37:20 -0000
*************** public class StackTraceElement implement
*** 192,196 ****
if (methodName != null)
sb.append(methodName);
! sb.append('(');
if (fileName != null)
sb.append(fileName);
--- 192,196 ----
if (methodName != null)
sb.append(methodName);
! sb.append(" (");
if (fileName != null)
sb.append(fileName);
Index: libjava/java/lang/Throwable.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/Throwable.java,v
retrieving revision 1.11
diff -c -2 -p -r1.11 Throwable.java
*** libjava/java/lang/Throwable.java 24 May 2002 10:40:42 -0000 1.11
--- libjava/java/lang/Throwable.java 11 Jul 2002 17:37:20 -0000
*************** import java.io.OutputStream;
*** 58,131 ****
*/
- /* A CPlusPlusDemangler sits on top of a PrintWriter. All input is
- * passed through the "c++filt" program (part of GNU binutils) which
- * demangles internal symbols to their C++ source form.
- *
- * Closing a CPlusPlusDemangler doesn't close the underlying
- * PrintWriter; it does, however close underlying process and flush
- * all its buffers, so it's possible to guarantee that after a
- * CPlusPlusDemangler has been closed no more will ever be written to
- * the underlying PrintWriter.
- *
- * FIXME: This implictly converts data from the input stream, which is
- * a stream of characters, to a stream of bytes. We need a way of
- * handling Unicode characters in demangled identifiers. */
-
- class CPlusPlusDemangler extends OutputStream
- {
- java.io.OutputStream procOut;
- java.io.InputStream procIn;
- java.lang.Process proc;
- PrintWriter p;
-
- /* The number of bytes written to the underlying PrintWriter. This
- provides a crude but fairly portable way to determine whether or
- not the attempt to exec c++filt worked. */
- public int written = 0;
-
- CPlusPlusDemangler (PrintWriter writer) throws IOException
- {
- p = writer;
- proc = Runtime.getRuntime ().exec ("c++filt -s java");
- procOut = proc.getOutputStream ();
- procIn = proc.getInputStream ();
- }
-
- public void write (int b) throws IOException
- {
- procOut.write (b);
- while (procIn.available () != 0)
- {
- int c = procIn.read ();
- if (c == -1)
- break;
- else
- {
- p.write (c);
- written++;
- }
- }
- }
-
- public void close () throws IOException
- {
- procOut.close ();
- int c;
- while ((c = procIn.read ()) != -1)
- {
- p.write (c);
- written++;
- }
- p.flush ();
- try
- {
- proc.waitFor ();
- }
- catch (InterruptedException _)
- {
- }
- }
- }
-
/**
* Throwable is the superclass of all exceptions that can be raised.
--- 58,61 ----
*************** public class Throwable implements Serial
*** 220,225 ****
* @since 1.4
*/
! // XXX Don't initialize this, once fillInStackTrace() does it.
! private StackTraceElement[] stackTrace = {};
/**
--- 150,154 ----
* @since 1.4
*/
! private StackTraceElement[] stackTrace;
/**
*************** public class Throwable implements Serial
*** 450,473 ****
/**
! * Print a stack trace to the specified PrintWriter. See
! * {@link #printStackTrace()} for the sample format.
*
* @param w the PrintWriter to write the trace to
* @since 1.1
*/
! public void printStackTrace (PrintWriter wr)
{
! try
{
! CPlusPlusDemangler cPlusPlusFilter = new CPlusPlusDemangler (wr);
! PrintWriter writer = new PrintWriter (cPlusPlusFilter);
! printRawStackTrace (writer);
! writer.close ();
! if (cPlusPlusFilter.written == 0) // The demangler has failed...
! printRawStackTrace (wr);
}
! catch (Exception e1)
{
! printRawStackTrace (wr);
}
}
--- 379,478 ----
/**
! * <p>Prints the exception, the detailed message and the stack trace
! * associated with this Throwable to the given <code>PrintWriter</code>.
! * The actual output written is implemention specific. Use the result of
! * <code>getStackTrace()</code> when more precise information is needed.
! *
! * <p>This implementation first prints a line with the result of this
! * object's <code>toString()</code> method.
! * <br>
! * Then for all elements given by <code>getStackTrace</code> it prints
! * a line containing three spaces, the string "at " and the result of calling
! * the <code>toString()</code> method on the <code>StackTraceElement</code>
! * object. If <code>getStackTrace()</code> returns an empty array it prints
! * a line containing three spaces and the string
! * "<<No stacktrace available>>".
! * <br>
! * Then if <code>getCause()</code> doesn't return null it adds a line
! * starting with "Caused by: " and the result of calling
! * <code>toString()</code> on the cause.
! * <br>
! * Then for every cause (of a cause, etc) the stacktrace is printed the
! * same as for the top level <code>Throwable</code> except that as soon
! * as all the remaining stack frames of the cause are the same as the
! * the last stack frames of the throwable that the cause is wrapped in
! * then a line starting with three spaces and the string "... X more" is
! * printed, where X is the number of remaining stackframes.
*
* @param w the PrintWriter to write the trace to
* @since 1.1
*/
! public void printStackTrace (PrintWriter pw)
{
! // First line
! pw.println(toString());
!
! // The 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]);
! }
!
! // The cause(s)
! Throwable cause = getCause();
! while (cause != null)
! {
! // Cause first line
! pw.println("Caused by: " + cause);
!
! // 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]);
! }
! else
! {
! boolean equal = false; // Is rest of stack equal to parent frame?
! for (int i = 0; i < stack.length && ! equal; i++)
! {
! // 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[element].equals(parentStack[parentElement]))
! {
! element++;
! parentElement++;
! }
! else
! equal = false;
! }
! // Print stacktrace element or indicate the rest is equal
! if (! equal)
! pw.println(" at " + stack[i]);
! else
! pw.println(" ..." + remaining + " more");
! }
! }
! cause = cause.getCause();
}
}
*************** public class Throwable implements Serial
*** 494,497 ****
--- 499,505 ----
public StackTraceElement[] getStackTrace()
{
+ if (stackTrace == null)
+ stackTrace = getStackTrace0();
+
return stackTrace;
}
*************** public class Throwable implements Serial
*** 514,519 ****
}
! private native final void printRawStackTrace (PrintWriter wr);
!
// Setting this flag to false prevents fillInStackTrace() from running.
static boolean trace_enabled = true;
--- 522,527 ----
}
! private native final StackTraceElement[] getStackTrace0 ();
!
// Setting this flag to false prevents fillInStackTrace() from running.
static boolean trace_enabled = true;
Index: libjava/java/lang/natThrowable.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/lang/natThrowable.cc,v
retrieving revision 1.12
diff -c -2 -p -r1.12 natThrowable.cc
*** libjava/java/lang/natThrowable.cc 24 May 2002 22:31:23 -0000 1.12
--- libjava/java/lang/natThrowable.cc 11 Jul 2002 17:37:20 -0000
*************** details. */
*** 23,26 ****
--- 23,27 ----
#include <java-threads.h>
#include <java/lang/Throwable.h>
+ #include <java/lang/StackTraceElement.h>
#include <java/io/PrintStream.h>
#include <java/io/PrintWriter.h>
*************** java::lang::Throwable::fillInStackTrace
*** 68,104 ****
}
! void
! java::lang::Throwable::printRawStackTrace (java::io::PrintWriter *wr)
{
- wr->println (toString ());
#ifdef HAVE_BACKTRACE
if (!stackTraceBytes)
! return;
int depth = stackTraceBytes->length / sizeof (void *);
void *p[depth];
memcpy (p, elements (stackTraceBytes), sizeof p);
_Jv_name_finder finder (_Jv_ThisExecutable ());
for (int i = 0; i < depth; i++)
! {
! bool found = finder.lookup (p[i]);
! wr->print (JvNewStringLatin1 (" at "));
! wr->print (JvNewStringLatin1 (finder.hex));
! if (found)
! {
! wr->print (JvNewStringLatin1 (": "));
! wr->print (JvNewStringLatin1 (finder.method_name));
! if (finder.file_name[0])
! {
! wr->print (JvNewStringLatin1 (" ("));
! wr->print (JvNewStringLatin1 (finder.file_name));
! wr->print (JvNewStringLatin1 (")"));
! }
! }
! wr->println ();
! }
#endif /* HAVE_BACKTRACE */
- wr->flush ();
}
--- 69,99 ----
}
! 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 */
}