aboutsummaryrefslogtreecommitdiff
path: root/libjava
diff options
context:
space:
mode:
authormark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>2002-07-12 12:52:44 +0000
committermark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>2002-07-12 12:52:44 +0000
commitec6c77248c565ea404891e933f58ecd7909fa674 (patch)
treefd16f76f98f4b5e364614153e8902a370d5f36e2 /libjava
parentcb39cd35980128baee5b7a01f68ed21b3f71da4b (diff)
* 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. * java/lang/StackTraceElement.java (toString): add extra whitespace. * gcj/javaprims.h: regenerate class list. * include/name-finder.h (lookup): new 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(). git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@55424 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava')
-rw-r--r--libjava/ChangeLog18
-rw-r--r--libjava/gcj/javaprims.h1
-rw-r--r--libjava/include/name-finder.h36
-rw-r--r--libjava/java/lang/StackTraceElement.java2
-rw-r--r--libjava/java/lang/Throwable.java180
-rw-r--r--libjava/java/lang/natThrowable.cc39
-rw-r--r--libjava/name-finder.cc224
7 files changed, 339 insertions, 161 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index f57f750b8d1..204836c3aa3 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,21 @@
+2002-07-12 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.
+ * java/lang/StackTraceElement.java (toString): add extra whitespace.
+ * gcj/javaprims.h: regenerate class list.
+ * include/name-finder.h (lookup): new 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().
+
2002-07-10 Tom Tromey <tromey@redhat.com>
* configure: Rebuilt.
diff --git a/libjava/gcj/javaprims.h b/libjava/gcj/javaprims.h
index 42104f8566b..99442c5ca2a 100644
--- a/libjava/gcj/javaprims.h
+++ b/libjava/gcj/javaprims.h
@@ -134,7 +134,6 @@ extern "Java"
class AssertionError;
class Boolean;
class Byte;
- class CPlusPlusDemangler;
class CharSequence;
class Character;
class Character$Subset;
diff --git a/libjava/include/name-finder.h b/libjava/include/name-finder.h
index 805725b4b69..67ae0587fb0 100644
--- a/libjava/include/name-finder.h
+++ b/libjava/include/name-finder.h
@@ -29,6 +29,8 @@ details. */
#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. */
@@ -47,12 +49,26 @@ public:
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
}
@@ -60,25 +76,21 @@ public:
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
- hex will have been correctly filled in with the pointer.
+ Returns NULL 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);
+ java::lang::StackTraceElement* lookup (void *p);
- char method_name[1024];
- char file_name[1024];
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;
- int f_pipe[2], b_pipe[2];
- FILE *b_pipe_fd;
- int error;
+ 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)
diff --git a/libjava/java/lang/StackTraceElement.java b/libjava/java/lang/StackTraceElement.java
index 9c60ab16410..d9e8a31b724 100644
--- a/libjava/java/lang/StackTraceElement.java
+++ b/libjava/java/lang/StackTraceElement.java
@@ -191,7 +191,7 @@ public class StackTraceElement implements Serializable
}
if (methodName != null)
sb.append(methodName);
- sb.append('(');
+ sb.append(" (");
if (fileName != null)
sb.append(fileName);
else
diff --git a/libjava/java/lang/Throwable.java b/libjava/java/lang/Throwable.java
index d5488b877e7..56c9d542a50 100644
--- a/libjava/java/lang/Throwable.java
+++ b/libjava/java/lang/Throwable.java
@@ -57,76 +57,6 @@ import java.io.OutputStream;
* bytecode not implemented. JDK 1.1.
*/
-/* 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.
*
@@ -219,8 +149,7 @@ public class Throwable implements Serializable
* no null entries
* @since 1.4
*/
- // XXX Don't initialize this, once fillInStackTrace() does it.
- private StackTraceElement[] stackTrace = {};
+ private StackTraceElement[] stackTrace;
/**
* Instantiate this Throwable with an empty message. The cause remains
@@ -449,26 +378,102 @@ public class Throwable implements Serializable
}
/**
- * Print a stack trace to the specified PrintWriter. See
- * {@link #printStackTrace()} for the sample format.
+ * <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
+ * "&lt;&lt;No stacktrace available&gt;&gt;".
+ * <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 wr)
+ public void printStackTrace (PrintWriter pw)
{
- try
+ // First line
+ pw.println(toString());
+
+ // The stacktrace
+ StackTraceElement[] stack = getStackTrace();
+ if (stack == null || stack.length == 0)
{
- CPlusPlusDemangler cPlusPlusFilter = new CPlusPlusDemangler (wr);
- PrintWriter writer = new PrintWriter (cPlusPlusFilter);
- printRawStackTrace (writer);
- writer.close ();
- if (cPlusPlusFilter.written == 0) // The demangler has failed...
- printRawStackTrace (wr);
+ pw.println(" <<No stacktrace available>>");
+ return;
}
- catch (Exception e1)
+ else
+ {
+ for (int i = 0; i < stack.length; i++)
+ pw.println(" at " + stack[i]);
+ }
+
+ // The cause(s)
+ Throwable cause = getCause();
+ while (cause != null)
{
- printRawStackTrace (wr);
+ // 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();
}
}
@@ -493,6 +498,9 @@ public class Throwable implements Serializable
*/
public StackTraceElement[] getStackTrace()
{
+ if (stackTrace == null)
+ stackTrace = getStackTrace0();
+
return stackTrace;
}
@@ -513,8 +521,8 @@ public class Throwable implements Serializable
this.stackTrace = stackTrace;
}
- private native final void printRawStackTrace (PrintWriter wr);
-
+ private native final StackTraceElement[] getStackTrace0 ();
+
// Setting this flag to false prevents fillInStackTrace() from running.
static boolean trace_enabled = true;
private transient byte stackTraceBytes[];
diff --git a/libjava/java/lang/natThrowable.cc b/libjava/java/lang/natThrowable.cc
index e6447086293..c2f7d1b8d8d 100644
--- a/libjava/java/lang/natThrowable.cc
+++ b/libjava/java/lang/natThrowable.cc
@@ -22,6 +22,7 @@ details. */
#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>
@@ -67,38 +68,32 @@ java::lang::Throwable::fillInStackTrace (void)
return this;
}
-void
-java::lang::Throwable::printRawStackTrace (java::io::PrintWriter *wr)
+JArray<java::lang::StackTraceElement*> *
+java::lang::Throwable::getStackTrace0 ()
{
- wr->println (toString ());
#ifdef HAVE_BACKTRACE
if (!stackTraceBytes)
- return;
+ 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++)
- {
- 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 ();
- }
+ el[i] = finder.lookup (p[i]);
+
+ return result;
+#else
+ return NULL;
#endif /* HAVE_BACKTRACE */
- wr->flush ();
}
diff --git a/libjava/name-finder.cc b/libjava/name-finder.cc
index a09ff0b267e..2d383aaa250 100644
--- a/libjava/name-finder.cc
+++ b/libjava/name-finder.cc
@@ -59,7 +59,7 @@ details. */
_Jv_name_finder::_Jv_name_finder (char *executable)
{
#if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
- error = 0;
+ demangling_error = lookup_error = 0;
// Initialize file descriptors so that shutdown works properly.
f_pipe[0] = -1;
@@ -68,14 +68,21 @@ _Jv_name_finder::_Jv_name_finder (char *executable)
b_pipe[1] = -1;
b_pipe_fd = NULL;
- char *argv[6];
+ 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++] = "-C";
argv[arg++] = "-f";
argv[arg++] = "-e";
#endif
@@ -83,10 +90,10 @@ _Jv_name_finder::_Jv_name_finder (char *executable)
argv[arg] = NULL;
}
- error |= pipe (f_pipe) < 0;
- error |= pipe (b_pipe) < 0;
+ lookup_error |= pipe (f_pipe) < 0;
+ lookup_error |= pipe (b_pipe) < 0;
- if (error)
+ if (lookup_error)
return;
pid = fork ();
@@ -109,18 +116,65 @@ _Jv_name_finder::_Jv_name_finder (char *executable)
if (pid < 0)
{
- error |= 1;
+ lookup_error |= 1;
return;
}
b_pipe_fd = fdopen (b_pipe[0], "r");
- error |= !b_pipe_fd;
+ lookup_error |= !b_pipe_fd;
- if (! error)
+ 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
}
@@ -144,6 +198,94 @@ _Jv_name_finder::toHex (void *p)
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.
@@ -151,12 +293,17 @@ _Jv_name_finder::toHex (void *p)
Returns false if the lookup fails. Even if this happens, the field
he will have been correctly filled in with the pointer. */
-bool
+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;
@@ -166,45 +313,44 @@ _Jv_name_finder::lookup (void *p)
if (dl_info.dli_fname)
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);
+ 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 true;
+ return createStackTraceElement (name, file_name);
}
}
#endif
+ memcpy (name, hex, strlen (hex) + 1);
+
#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;
+ 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;
-#else
- return false;
+ {
+ 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));
}