libgcj/5773: integrate addr2line and c++filt into libjava instead of external process

toddastock@yahoo.com toddastock@yahoo.com
Sun Feb 24 17:26:00 GMT 2002


>Number:         5773
>Category:       libgcj
>Synopsis:       integrate addr2line and c++filter into libjava instead of using an external process.
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Feb 24 17:26:01 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     
>Release:        3.1 20020224 (experimental)
>Organization:
>Environment:
System: Linux escher 2.4.9-21 #1 Thu Jan 17 14:16:30 EST 2002 i686 unknown
Architecture: i686

	
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with: ./configure --enable-threads=posix --prefix=/home/tstock/local --disable-shared --enable-languages=c++,java : (reconfigured) 
>Description:
I was having problems with the fork within a thread.  So I took the code from binutils and created an integrated function method and name lookup.
>How-To-Repeat:
It's less of a bug and more of an annoyance.  The following code is not working consistantly on my machine and spurred the changes:
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

extern char **environ;

void *func( void * arg )
  {
  pid_t pid;
  int inp[2], outp[2], errp[2], msgp[2];
  char **env = NULL;

  if (pipe (inp))
    exit (1);
  if (pipe (outp))
    exit (1);
  if (pipe (errp))
    exit (1);
  if (pipe (msgp))
    exit (1);
  if (fcntl (msgp[1], F_SETFD, FD_CLOEXEC))
    exit (1);

  if ((pid = fork ()) == -1)
    exit (2);

  if (pid == 0)
    {
      // Use close and not myclose -- we're in the child, and we
      // aren't worried about the possible race condition.
      close (inp[0]);
//      close (inp[1]);
      close (errp[0]);
//      close (errp[1]);
//      close (outp[0]);
      close (outp[1]);
      close (msgp[0]);

      char *args[4];

      args[0] = "c++filt";
      args[1] = "-s";
      args[2] = "gnu";
      args[3] = NULL;

      char *path_val = getenv ("PATH");
      environ = env;
      if (getenv ("PATH") == NULL)
        {
          char *path_env = (char *) malloc (strlen (path_val) + 5 + 1);
          strcpy (path_env, "PATH=");
          strcat (path_env, ".");
          putenv (path_env);
        }

      // We ignore errors from dup2 because they should never occur.
      dup2 (outp[0], 0);
      dup2 (inp[1], 1);
      dup2 (errp[1], 2);

      execvp (args[0], args);

      char c = errno;
      // Send the parent notification that the exec failed.
      write (msgp[1], &c, 1);
      _exit(127);
    }

  // Parent.  Close extra file descriptors and mark ours as
  // close-on-exec.
  close (outp[0]);
  close (inp[1]);
  close (errp[1]);
  close (msgp[1]);

  char c;
  int r = read (msgp[0], &c, 1);
  if (r == -1)
    exit (3);
  else if (r != 0)
    exit (3);

  close (msgp[0]);

  fcntl (outp[1], F_SETFD, 1);
  fcntl (inp[0], F_SETFD, 1);
  fcntl (errp[0], F_SETFD, 1);
  return NULL;
  }

int main (int argc, char **argv)
  {
    pthread_t th;
    pthread_attr_t tha;
    pthread_attr_init( &tha );
    pthread_create( &th, &tha, func, NULL );
  }
>Fix:
I wrote an addr2line class to deal with the name conversion; code from binutils.  I also modifed the make file and stuff.  I do an external check for the libbfd library to get the bfd routines.  If they don't exist then we fall back on the old method.

Added programs:
--------------------------------------------------------------------------------
// addr2line.cc - Convert addresses to names

/* Copyright (C) 2000  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 Todd Stock <toddastock@yahoo.com>
 * @date Feb 24  2002
 */

#include <config.h>

#ifdef HAVE_LIBBFD

#include <jvm.h>
#include <gcj/cni.h>

#include <addr2line.h>

#include <stdio.h>
#include <stdlib.h>

extern "C" {
#include "demangle.h"
}

void free(void *);

static void
addr2LineErrorHandler (const char *s, ...)
  {
  }

Addr2Line::Addr2Line (char *executable)
  {
    char **matching;

    abfd = NULL;

    bfd_init ();

    bfd_set_error_handler( addr2LineErrorHandler );

    const char *target = TARGET;
    if (! bfd_set_default_target (target))
      {
        fprintf( stderr, "can't set BFD default target to `%s': %s", target, bfd_errmsg (bfd_get_error ()));
        return;
      }

    abfd = bfd_openr (executable, NULL);
    if (abfd == NULL)
      {
        printErr( executable );
        return;
      }

    if (bfd_check_format (abfd, bfd_archive))
      {
        fprintf( stderr, "%s: can not get addresses from archive", executable );
        bfd_close (abfd);
        abfd = NULL;
        return;
      }

    if (! bfd_check_format_matches (abfd, bfd_object, &matching))
      {
        printErr ( bfd_get_filename (abfd) );
        if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
          {
//	    list_matching_formats (matching);
	    free(matching);
	  }
        bfd_close (abfd);
        abfd = NULL;
        return;
      }

    long storage;
    long symcount;

    if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0)
      {
        bfd_close (abfd);
        abfd = NULL;
        return;
      }

    storage = bfd_get_symtab_upper_bound (abfd);
    if (storage < 0)
      {
        printErr ( bfd_get_filename (abfd) );
        bfd_close (abfd);
        abfd = NULL;
        return;
      }

    syms = (asymbol **) _Jv_Malloc(storage);

    symcount = bfd_canonicalize_symtab (abfd, syms);
    if (symcount < 0)
      {
        printErr ( bfd_get_filename (abfd) );
        bfd_close (abfd);
        abfd = NULL;
        _Jv_Free (syms);
        syms = NULL;
        return;
      }

    needFree = found = false;
    methodName = "??";
    fileName = NULL;
    line = 0;
  }

Addr2Line::~Addr2Line ()
  {
    if (syms != NULL)
      { 
        _Jv_Free (syms);
        syms = NULL;
      }

    if (abfd != NULL)
      {
        bfd_close (abfd);
      }
  }

void
find_address_in_section ( bfd *abfd, asection *section, void *data)
  {
    bfd_vma vma;
    bfd_size_type size;
    Addr2Line *x = (Addr2Line *)data;

    if (x->found)
      return;

    if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0)
      return;

    vma = bfd_get_section_vma (abfd, section);
    if (x->pc < vma)
      return;

    size = bfd_get_section_size_before_reloc (section);
    if (x->pc >= vma + size)
      return;

    x->found = bfd_find_nearest_line (abfd, section, x->syms, x->pc - vma, &x->fileName, &x->_methodName, (unsigned int *)&x->line);
  }

bool
Addr2Line::lookup (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;
  return _lookup( hex );
}

bool
Addr2Line::_lookup( char *addr_hex )
  {
    if( needFree ) {
      free( methodName );
    }
    needFree = false;

    if (addr_hex == NULL)
      return false;

    pc = bfd_scan_vma( addr_hex, NULL, 16 );

    found = false;
    methodName = "??";
    fileName = NULL;
    line = 0;

    if (abfd == NULL)
      return false;

    bfd_map_over_sections( abfd, find_address_in_section, this );
    if( found )
      {
        if( _methodName == NULL )
          {
            methodName = "??";
          }
        else
          {
            needFree = true;
            char *res = cplus_demangle( _methodName,  DMGL_ANSI | DMGL_PARAMS );
            if (res == NULL)
            {
              methodName = strdup(_methodName);
            }
          else
            {
              methodName = res;
            }
        }
        return true;
      }
    return false;
  }

void
Addr2Line::printErr( char *string )
  {
    const char *errmsg = bfd_errmsg (bfd_get_error ());
    if (string)
      fprintf (stderr, "Addr2Line: %s: %s\n", string, errmsg);
    else
      fprintf (stderr, "Addr2Line: %s\n", errmsg);
  }

#endif
--------------------------------------------------------------------------------
// addr2line.h - Convert addresses to names (header)

/* Copyright (C) 2000  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 Todd Stock <toddastock@yahoo.com>
 * @date Feb 24  2002
 */

#ifndef ADDR2LINE
#define ADDR2LINE

#include <bfd.h>

class Addr2Line
  {

public:

    Addr2Line (char *);
    ~Addr2Line ();

    void *operator new (size_t bytes)
      {
        return _Jv_Malloc (bytes);
      }

    void operator delete (void *mem)
      {
        _Jv_Free (mem);
      }

    bool lookup (void *);

    char *methodName;
    const char *fileName;
    jlong line;
    char hex[sizeof (void *) * 2 + 5];

private:

    friend void find_address_in_section (bfd *, asection *, void *);
    bool _lookup (char *);
    void printErr (char *);

    const char *_methodName;
    bfd *abfd;
    asymbol **syms;
    bfd_vma pc;
    bool found;
    bool needFree;
  };
#endif
--------------------------------------------------------------------------------
// CPlusPlusDemangler.java

/* Copyright (C) 1998, 1999  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 java.lang;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.OutputStreamWriter;
import java.io.OutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;

/**
 * @author Tom Tromey <tromey@cygnus.com>
 * @date October 30, 1998 
 * modified by Todd Stock on Feb 24, 2002
 */

/* 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
 * 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
{
  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;
    _init( );
  }

  public native void _init ();

  public native void write (int b) throws IOException;
  
  public void close () throws IOException
  {
    p.flush ();
  }    
}
--------------------------------------------------------------------------------
Changes to programs:
+ cvs -z9 -q diff -u Makefile.am acconfig.h configure.in prims.cc include/config.h.in java/lang/Throwable.java java/lang/natThrowable.cc
Index: Makefile.am
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.201
diff -u -r1.201 Makefile.am
--- Makefile.am	22 Feb 2002 03:21:26 -0000	1.201
+++ Makefile.am	25 Feb 2002 01:01:14 -0000
@@ -82,6 +82,7 @@
 JAVAC = $(GCJ_WITH_FLAGS) -C
 
 GCC_UNWIND_INCLUDE = @GCC_UNWIND_INCLUDE@
+GCC_TOP_INCLUDE = @GCC_TOP_INCLUDE@
 
 WARNINGS = -W -Wall
 ## We need _GNU_SOURCE defined for some Linux builds.  It doesn't hurt
@@ -104,7 +105,7 @@
 
 INCLUDES = -I$(top_srcdir) -Iinclude -I$(top_srcdir)/include \
 	$(GCINCS) $(THREADINCS) $(INCLTDL) \
-	$(GCC_UNWIND_INCLUDE) $(ZINCS) $(LIBFFIINCS)
+	$(GCC_UNWIND_INCLUDE) $(GCC_TOP_INCLUDE) $(ZINCS) $(LIBFFIINCS)
 
 
 ## ################################################################
@@ -125,7 +126,7 @@
 
 libgcj_la_SOURCES = prims.cc jni.cc exception.cc \
 	resolve.cc defineclass.cc interpret.cc name-finder.cc verify.cc \
-	$(nat_source_files)
+	$(nat_source_files) addr2line.cc
 EXTRA_libgcj_la_SOURCES = boehm.cc nogc.cc posix-threads.cc no-threads.cc \
 	win32-threads.cc posix.cc win32.cc \
 	$(c_source_files) $(java_source_files) $(built_java_source_files)
@@ -1111,6 +1112,7 @@
 java/lang/ThreadDeath.java \
 java/lang/ThreadGroup.java \
 java/lang/ThreadLocal.java \
+java/lang/CPlusPlusDemangler.java \
 java/lang/Throwable.java \
 java/lang/UnknownError.java \
 java/lang/UnsatisfiedLinkError.java \
Index: acconfig.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/acconfig.h,v
retrieving revision 1.22
diff -u -r1.22 acconfig.h
--- acconfig.h	7 Feb 2002 03:24:08 -0000	1.22
+++ acconfig.h	25 Feb 2002 01:01:14 -0000
@@ -152,3 +152,6 @@
 
 /* Define if you are using JVMPI.  */
 #undef ENABLE_JVMPI
+
+/* has -lbfd */
+#undef HAVE_LIBBFD
Index: configure.in
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/configure.in,v
retrieving revision 1.114
diff -u -r1.114 configure.in
--- configure.in	12 Feb 2002 05:52:30 -0000	1.114
+++ configure.in	25 Feb 2002 01:01:16 -0000
@@ -13,6 +13,7 @@
 LIBGCJ_CONFIGURE(.)
 
 AM_CONFIG_HEADER(include/config.h gcj/libgcj-config.h)
+AC_DEFINE_UNQUOTED(TARGET, "${target}", [Configured target name.])
 
 # Only use libltdl for native builds.
 if test -z "${with_cross_host}"; then
@@ -325,6 +326,8 @@
 AC_SUBST(GCTESTSPEC)
 AC_LINK_FILES(include/$GCHDR, include/java-gc.h)
 
+LIBERTYLIBS="-L\$(here)/../libiberty -liberty"
+AC_SUBST(LIBERTYLIBS)
 
 AC_MSG_CHECKING([for thread model used by GCC])
 THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
@@ -439,6 +442,7 @@
 
 # We're in the tree with gcc, and need to include some of its headers.
 GCC_UNWIND_INCLUDE='-I$(libgcj_basedir)/../gcc'
+GCC_TOP_INCLUDE='-I$(libgcj_basedir)/../include'
 
 if test -n "${with_cross_host}"; then
    # We are being configured with a cross compiler.  AC_REPLACE_FUNCS
@@ -468,6 +472,7 @@
    if test x"$build" != x"$with_cross_host" && x"$build" != x"$target"; then
       CANADIAN=yes
       GCC_UNWIND_INCLUDE=
+      GCC_TOP_INCLUDE=
       GCJ="${target_alias}-gcj"
    fi
    NATIVE=no
@@ -670,6 +675,8 @@
    if test "$GC" = boehm; then
       AC_CHECK_LIB(dl, main, SYSTEMSPEC="$SYSTEMSPEC -ldl")
    fi
+#   AC_CHECK_LIB(iberty, main)
+   AC_CHECK_LIB(bfd, main,[AC_DEFINE(HAVE_LIBBFD) LIBS="$LIBS -lbfd $LIBERTYLIBS"],,$LIBERTYLIBS)
 
    if test -z "${with_multisubdir}"; then
       builddotdot=.
@@ -742,6 +749,7 @@
 AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host")
 AM_CONDITIONAL(NEEDS_DATA_START, test "$NEEDS_DATA_START" = yes && test "$NATIVE" = yes)
 AC_SUBST(GCC_UNWIND_INCLUDE)
+AC_SUBST(GCC_TOP_INCLUDE)
 
 # Determine gcj version number.
 changequote(<<,>>)
Index: prims.cc
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/prims.cc,v
retrieving revision 1.71
diff -u -r1.71 prims.cc
--- prims.cc	7 Feb 2002 18:59:50 -0000	1.71
+++ prims.cc	25 Feb 2002 01:01:19 -0000
@@ -39,6 +39,9 @@
 #define PROCESS_GCJ_PROPERTIES
 #endif // DISABLE_GETENV_PROPERTIES
 
+#ifdef HAVE_LIBBFD
+#include <addr2line.h>
+#endif
 #include <java/lang/Class.h>
 #include <java/lang/ClassLoader.h>
 #include <java/lang/Runtime.h>
@@ -92,6 +95,11 @@
 const char **_Jv_argv;
 int _Jv_argc;
 
+#ifdef HAVE_LIBBFD
+// Name finder code.
+Addr2Line *addr2Line = NULL;
+#endif
+
 #ifdef ENABLE_JVMPI
 // Pointer to JVMPI notification functions.
 void (*_Jv_JVMPI_Notify_OBJECT_ALLOC) (JVMPI_Event *event);
@@ -959,6 +967,9 @@
 
   java::lang::Runtime *runtime = NULL;
 
+#ifdef HAVE_LIBBFD
+  addr2Line = NULL;
+#endif
 
 #ifdef DISABLE_MAIN_ARGS
   _Jv_ThisExecutable ("[Embedded App]");
@@ -967,8 +978,14 @@
   char exec_name[20];
   sprintf (exec_name, "/proc/%d/exe", getpid ());
   _Jv_ThisExecutable (exec_name);
+#ifdef HAVE_LIBBFD
+  addr2Line = new Addr2Line( exec_name );
+#endif
 #else
   _Jv_ThisExecutable (argv[0]);
+#ifdef HAVE_LIBBFD
+  addr2Line = new Addr2Line( argv[0] );
+#endif
 #endif /* HAVE_PROC_SELF_EXE */
 #endif /* DISABLE_MAIN_ARGS */
 
Index: include/config.h.in
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/include/config.h.in,v
retrieving revision 1.38
diff -u -r1.38 config.h.in
--- include/config.h.in	7 Feb 2002 19:25:28 -0000	1.38
+++ include/config.h.in	25 Feb 2002 01:01:20 -0000
@@ -176,6 +176,9 @@
 /* Define if you are using JVMPI.  */
 #undef ENABLE_JVMPI
 
+/* has -lbfd */
+#undef HAVE_LIBBFD
+
 /* Define if you have the access function.  */
 #undef HAVE_ACCESS
 
@@ -382,6 +385,9 @@
 
 /* Version number of package */
 #undef VERSION
+
+/* Configured target name. */
+#undef TARGET
 
 /* Define if the compiler is configured for setjmp/longjmp exceptions. */
 #undef SJLJ_EXCEPTIONS
Index: java/lang/Throwable.java
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/java/lang/Throwable.java,v
retrieving revision 1.10
diff -u -r1.10 Throwable.java
--- java/lang/Throwable.java	24 Feb 2001 03:52:49 -0000	1.10
+++ java/lang/Throwable.java	25 Feb 2002 01:01:20 -0000
@@ -28,76 +28,6 @@
  * 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 _)
-      {
-      }
-  }    
-}
-
 public class Throwable implements Serializable
 {
   public native Throwable fillInStackTrace ();
Index: java/lang/natThrowable.cc
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/java/lang/natThrowable.cc,v
retrieving revision 1.11
diff -u -r1.11 natThrowable.cc
--- java/lang/natThrowable.cc	7 Feb 2002 19:26:06 -0000	1.11
+++ java/lang/natThrowable.cc	25 Feb 2002 01:01:20 -0000
@@ -21,7 +21,9 @@
 #include <jvm.h>
 #include <java/lang/Object.h>
 #include <java-threads.h>
+#include <java/lang/CPlusPlusDemangler.h>
 #include <java/lang/Throwable.h>
+#include <java/lang/StringBuffer.h>
 #include <java/io/PrintStream.h>
 #include <java/io/PrintWriter.h>
 #include <java/io/IOException.h>
@@ -30,6 +32,17 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <ctype.h>
+#include <libiberty.h>
+extern "C" {
+#include <demangle.h>
+}
+
+/*
+// Declared static in liberty so we can't use..
+extern const char *
+standard_symbol_characters PARAMS ((void));
+*/
 
 #include <unistd.h>
 
@@ -39,6 +52,87 @@
 
 #include <name-finder.h>
 
+#ifdef HAVE_LIBBFD
+#include <addr2line.h>
+extern Addr2Line *addr2Line;
+#endif
+
+#define MBUF_SIZE 32767
+char mbuffer[MBUF_SIZE];
+int mbufferpos = 0;
+static int flags = DMGL_PARAMS | DMGL_ANSI;
+static enum demangling_styles style = auto_demangling;
+ 
+void
+java::lang::CPlusPlusDemangler::_init ()
+  {
+    style = cplus_demangle_name_to_style ("java");
+    if( style == unknown_demangling )
+      style = auto_demangling;
+    cplus_demangle_set_style(style);
+  }
+
+void
+java::lang::CPlusPlusDemangler::write (jint c)
+  {
+
+    if( c != EOF && ((isascii (c) && isalnum(c)) || strchr(/*standard_symbol_characters ()*/ "_$.", c)) )
+      {
+        if( mbufferpos < MBUF_SIZE-1 )
+          {
+            mbuffer[mbufferpos++] = c;
+            return;
+          }
+      }
+    if( mbufferpos > 0 )
+      {
+        int skip_first = 0;
+
+        if (mbuffer[0] == '.' || mbuffer[0] == '$')
+        ++skip_first;
+        if (/*strip_underscore &&*/ mbuffer[skip_first] == '_')
+        ++skip_first;
+
+        if (skip_first > mbufferpos)
+          skip_first = mbufferpos;
+
+        mbuffer[mbufferpos] = 0;
+
+        flags |= (int) style;
+        char * result = cplus_demangle (mbuffer + skip_first, flags);
+        if (result)
+          {
+            if (mbuffer[0] == '.')
+              {
+                p->write ((jchar)'.');
+                written++;
+              }
+            for( unsigned int j=0; j<strlen(result); j++ )
+              {
+                p->write ((jchar)result[j]);
+                written++;
+              }
+            free (result);
+          }
+        else
+          {
+            for( unsigned int j=0; j<strlen(mbuffer); j++ )
+              {
+                p->write ((jchar)mbuffer[j]);
+                written++;
+              }
+          }
+
+        p->flush();
+        mbufferpos = 0;
+      }
+    if (c == EOF)
+      return;
+    p->write ((jchar)c);
+    written++;
+    p->flush();
+  }
+
 /* 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.  */
@@ -79,6 +173,28 @@
   void *p[depth];
   memcpy (p, elements (stackTrace), sizeof p);
 
+#if defined(HAVE_LIBBFD) && !defined(DISABLE_MAIN_ARGS)
+  for (int i = 0; i < depth; i++)
+    {
+      bool found = addr2Line->lookup (p[i]);
+      wr->print (JvNewStringLatin1 ("   at "));
+      wr->print (JvNewStringLatin1 (addr2Line->hex));
+      if (found)
+	{
+	  wr->print (JvNewStringLatin1 (": "));
+	  wr->print (JvNewStringLatin1 (addr2Line->methodName));
+	  if (addr2Line->fileName)
+	    {
+	      wr->print (JvNewStringLatin1 (" ("));
+	      wr->print (JvNewStringLatin1 (addr2Line->fileName));
+	      wr->print (JvNewStringLatin1 (":"));
+	      wr->print (addr2Line->line);
+	      wr->print (JvNewStringLatin1 (")"));
+	    }
+	}
+      wr->println ();
+    }
+#else
   _Jv_name_finder finder (_Jv_ThisExecutable ());
 
   for (int i = 0; i < depth; i++)
@@ -99,6 +215,7 @@
 	}
       wr->println ();
     }
+#endif
 #endif /* HAVE_BACKTRACE */
   wr->flush ();
 }
>Release-Note:
>Audit-Trail:
>Unformatted:



More information about the Java-prs mailing list