This is the mail archive of the java@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]

RFC: stack trace generation


Hi,

Something I've been working on recently is finding a way to get a
decent Java stack trace, complete with file and line number
information, without using external processes (the problems with GCJ's
Process implementation notwithstanding, the current method is too
slow, and doesn't work on my target platform when a lot of the code is
in shared libraries).

I've modified gnu.gcj.runtime.NameFinder so that it does two things
differently: the first, it uses StackTrace to determine the class and
method name of each frame, instead of demangling symbols. I don't know
why the code doesn't do it this way already, since it looks to me to
be faster and more reliable; are the StackTrace methods less reliable
than I think they are?

Secondly, for code loaded from shared libraries, NameFinder looks up
the DWARF-2 debug_line section, and reads the file and line number
from that. This works, and I can get accurate debug stack traces, but
even that is slow, especially when resolving names in a large library
(like libgcj.so).

There are ways to speed this up, of course. As is, the code has to
parse the debug info for every PC in the stack, which is wildly
inefficient. A better way to do this would be to look up all addresses
in the stack at once, and to keep a running map between PC and debug
info. I think it would be possible to even allow pluggable name
resolvers, where NameFinder will try each in sequence to try to make
as complete a stack trace as possible; but even without a pluggable
architecture we could still have, at minimum, a DWARF-2 reader and
the info provided by Mark's interpreter patch.

I'd like to know what people think of this idea -- to change the
semantics of NameFinder so it looks up the stack as a whole, and
whether or not a pluggable resolver is a good idea. Since I don't want
to assume that every platform uses DWARF-2, I thought it might be good
to leave room for other methods.

I will attach what I've come up with so far, but I don't consider this
patch complete.

-- 
Casey Marshall || csm@gnu.org
Index: libjava/Makefile.am
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.382
diff -u -r1.382 Makefile.am
--- libjava/Makefile.am	17 Jun 2004 23:43:09 -0000	1.382
+++ libjava/Makefile.am	16 Jul 2004 03:14:36 -0000
@@ -471,6 +471,13 @@
 $(c_files): %.lo: %.c
 	$(LTCOMPILE) -c -o $@ $<
 
+## A special rule for interpret.lo for the time being.  Our current
+## approach to stack-trace handling is fragile and will not work with
+## unit-at-a-time.  So, for now we disable it.  This will be fixed by
+## a larger patch in the future.
+interpret.lo: interpret.cc
+	$(LTCXXCOMPILE) -fno-unit-at-a-time -c -o $@ $<
+
 $(extra_cc_files): %.lo: %.cc
 	$(LTCXXCOMPILE) -c -o $@ $<
 
@@ -2262,6 +2269,7 @@
 gnu/gcj/io/DefaultMimeTypes.java \
 gnu/gcj/io/MimeTypes.java \
 gnu/gcj/io/SimpleSHSStream.java	\
+gnu/gcj/runtime/DebugInfo.java \
 gnu/gcj/runtime/FileDeleter.java \
 gnu/gcj/runtime/FinalizerThread.java \
 gnu/gcj/runtime/FirstThread.java \
Index: libjava/Makefile.in
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/Makefile.in,v
retrieving revision 1.406
diff -u -r1.406 Makefile.in
--- libjava/Makefile.in	17 Jun 2004 23:43:09 -0000	1.406
+++ libjava/Makefile.in	16 Jul 2004 03:14:37 -0000
@@ -1934,6 +1934,7 @@
 gnu/gcj/io/DefaultMimeTypes.java \
 gnu/gcj/io/MimeTypes.java \
 gnu/gcj/io/SimpleSHSStream.java	\
+gnu/gcj/runtime/DebugInfo.java \
 gnu/gcj/runtime/FileDeleter.java \
 gnu/gcj/runtime/FinalizerThread.java \
 gnu/gcj/runtime/FirstThread.java \
@@ -3084,8 +3085,8 @@
 .deps/gnu/classpath/ServiceFactory.P \
 .deps/gnu/classpath/ServiceProviderLoadingAction.P .deps/gnu/gcj/Core.P \
 .deps/gnu/gcj/RawData.P .deps/gnu/gcj/RawDataManaged.P \
-.deps/gnu/gcj/convert/BytesToUnicode.P \
-.deps/gnu/gcj/convert/Convert.P .deps/gnu/gcj/convert/IOConverter.P \
+.deps/gnu/gcj/convert/BytesToUnicode.P .deps/gnu/gcj/convert/Convert.P \
+.deps/gnu/gcj/convert/IOConverter.P \
 .deps/gnu/gcj/convert/Input_8859_1.P \
 .deps/gnu/gcj/convert/Input_ASCII.P \
 .deps/gnu/gcj/convert/Input_EUCJIS.P \
@@ -3111,7 +3112,8 @@
 .deps/gnu/gcj/io/DefaultMimeTypes.P .deps/gnu/gcj/io/MimeTypes.P \
 .deps/gnu/gcj/io/SimpleSHSStream.P \
 .deps/gnu/gcj/io/natSimpleSHSStream.P .deps/gnu/gcj/io/shs.P \
-.deps/gnu/gcj/natCore.P .deps/gnu/gcj/runtime/FileDeleter.P \
+.deps/gnu/gcj/natCore.P .deps/gnu/gcj/runtime/DebugInfo.P \
+.deps/gnu/gcj/runtime/FileDeleter.P \
 .deps/gnu/gcj/runtime/FinalizerThread.P \
 .deps/gnu/gcj/runtime/FirstThread.P .deps/gnu/gcj/runtime/JNIWeakRef.P \
 .deps/gnu/gcj/runtime/MethodRef.P .deps/gnu/gcj/runtime/NameFinder.P \
@@ -3480,8 +3482,7 @@
 .deps/gnu/java/util/prefs/MemoryBasedFactory.P \
 .deps/gnu/java/util/prefs/MemoryBasedPreferences.P \
 .deps/gnu/java/util/prefs/NodeReader.P \
-.deps/gnu/java/util/prefs/NodeWriter.P \
-.deps/gnu/regexp/CharIndexed.P \
+.deps/gnu/java/util/prefs/NodeWriter.P .deps/gnu/regexp/CharIndexed.P \
 .deps/gnu/regexp/CharIndexedCharArray.P \
 .deps/gnu/regexp/CharIndexedInputStream.P \
 .deps/gnu/regexp/CharIndexedString.P \
@@ -5475,6 +5476,9 @@
 $(c_files): %.lo: %.c
 	$(LTCOMPILE) -c -o $@ $<
 
+interpret.lo: interpret.cc
+	$(LTCXXCOMPILE) -fno-unit-at-a-time -c -o $@ $<
+
 $(extra_cc_files): %.lo: %.cc
 	$(LTCXXCOMPILE) -c -o $@ $<
 
Index: libjava/configure
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/configure,v
retrieving revision 1.208
diff -u -r1.208 configure
--- libjava/configure	14 Jun 2004 18:28:56 -0000	1.208
+++ libjava/configure	16 Jul 2004 03:14:38 -0000
@@ -5043,7 +5043,7 @@
 fi
 done
 
-   for ac_hdr in execinfo.h unistd.h dlfcn.h
+   for ac_hdr in execinfo.h unistd.h dlfcn.h link.h elf.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
Index: libjava/configure.in
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/configure.in,v
retrieving revision 1.185
diff -u -r1.185 configure.in
--- libjava/configure.in	14 Jun 2004 18:29:01 -0000	1.185
+++ libjava/configure.in	16 Jul 2004 03:14:38 -0000
@@ -652,7 +652,7 @@
    AC_CHECK_FUNCS(inet_aton inet_addr, break)
    AC_CHECK_FUNCS(inet_pton uname inet_ntoa)
    AC_CHECK_FUNCS(fork execvp pipe sigaction ftruncate)
-   AC_CHECK_HEADERS(execinfo.h unistd.h dlfcn.h) 
+   AC_CHECK_HEADERS(execinfo.h unistd.h dlfcn.h link.h elf.h) 
    AC_CHECK_FUNC(backtrace, [
      case "$host" in
        ia64-*-linux*)
Index: libjava/gnu/gcj/runtime/NameFinder.java
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/gnu/gcj/runtime/NameFinder.java,v
retrieving revision 1.7
diff -u -r1.7 NameFinder.java
--- libjava/gnu/gcj/runtime/NameFinder.java	9 Apr 2004 04:39:24 -0000	1.7
+++ libjava/gnu/gcj/runtime/NameFinder.java	16 Jul 2004 03:14:46 -0000
@@ -54,32 +54,32 @@
  * 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();
+          = 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();
+          = 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();
+          = Boolean.valueOf(System.getProperty
+                ("gnu.gcj.runtime.NameFinder.remove_unknown", "true")
+            ).booleanValue();
   private static final boolean remove_interpreter
-	  = Boolean.valueOf(System.getProperty
-		("gnu.gcj.runtime.NameFinder.remove_interpreter", "true")
-	    ).booleanValue();
+          = Boolean.valueOf(System.getProperty
+                ("gnu.gcj.runtime.NameFinder.remove_interpreter", "true")
+            ).booleanValue();
   private static final boolean use_addr2line
-	  = Boolean.valueOf(System.getProperty
-		("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
-	    ).booleanValue();
+          = Boolean.valueOf(System.getProperty
+                ("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
+            ).booleanValue();
 
   /**
    * The name of the currently running executable.
@@ -115,50 +115,25 @@
   {
     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 BufferedWriter
-			(new OutputStreamWriter(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[] {"addr2name.awk", executable};
-		addr2line = runtime.exec(exec);
-		usingAddr2name = true;
-	      }
-	    catch (IOException ioe2) { addr2line = null; }
-	  }
-
-	if (addr2line != null)
-	  {
-	    addr2lineIn = new BufferedReader
-	      (new InputStreamReader(addr2line.getInputStream()));
-	    addr2lineOut = new BufferedWriter
-	      (new OutputStreamWriter(addr2line.getOutputStream()));
-	  }
+        try
+          {
+            String[] exec = new String[] {"addr2line", "-e", executable};
+            addr2line = runtime.exec(exec);
+          }
+        catch (IOException ioe)
+          {
+          }
+
+        if (addr2line != null)
+          {
+            addr2lineIn = new BufferedReader
+              (new InputStreamReader(addr2line.getInputStream()));
+            addr2lineOut = new BufferedWriter
+              (new OutputStreamWriter(addr2line.getOutputStream()));
+          }
       }
   }
 
@@ -171,7 +146,13 @@
    * Tries to use dladdr to create the nth StackTraceElement from the given
    * addresses. Returns null on failure.
    */
-  native private StackTraceElement dladdrLookup(RawData addrs, int n);
+  native private DebugInfo dladdrLookup(RawData addrs, int n);
+
+  /**
+   * Tries to read the DWARF-2 debugging info from natively compiled
+   * methods in shared libraries, if present.
+   */
+  native private DebugInfo dwarf2Lookup(RawData addrs, int n);
 
   /**
    * Returns the nth element from the stack as a hex encoded String.
@@ -187,53 +168,68 @@
    * If nth element of stack is an interpreted frame, return the
    * element representing the method being interpreted.
    */
-  native private StackTraceElement lookupInterp(RawData addrs, int n);
+  native private DebugInfo lookupInterp(RawData addrs, int n);
 
   /**
    * Creates the nth StackTraceElement from the given native stacktrace.
    */
-  private StackTraceElement lookup(RawData addrs, int n)
+  private StackTraceElement lookup(RawData addrs, int n, StackTrace trace)
   {
     StackTraceElement result;
+    Class clazz = trace.classAt(n);
+    String classname = clazz != null ? clazz.getName() : null;
+    String method = trace.methodAt(n);
+    DebugInfo info = null;
+    boolean nat = false;
 
-    result = lookupInterp(addrs, n);
-    if (result == null)
-      result = dladdrLookup(addrs, n);
-    if (result == null)
-      {
-	String name = null;
-	String file = null;
-
-	String hex = getAddrAsString(addrs, n);
-	
-	if (addr2line != null)
-	  {
-	    try
-	      {
-		addr2lineOut.write(hex);
-		addr2lineOut.newLine();
-		addr2lineOut.flush();
-		name = addr2lineIn.readLine();
-		file = addr2lineIn.readLine();
-
-                // addr2line uses symbolic debugging information instead
-                // of the actually exported labels as addr2name.awk does.
-                // This name might need some modification, depending on 
-                // the system, to make it a label like that returned 
-                // by addr2name.awk or dladdr.
-                if (! usingAddr2name)
-                  if (name != null && ! "??".equals (name))
-                    name = getExternalLabel (name);
-	      }
-	    catch (IOException ioe) { addr2line = null; }
-	  }
+    info = lookupInterp(addrs, n);
+    if (info == null)
+      {
+        info = dwarf2Lookup(addrs, n);
+        if (info != null)
+          nat = true;
+      }
+    if (info == null)
+      {
+        info = dladdrLookup(addrs, n);
+        if (info != null)
+          nat = true;
+      }
+    if (info == null)
+      {
+        String file = null;
+        int line = -1;
 
-	if (name == null || "??".equals(name))
-	  name = hex;
+        String hex = getAddrAsString(addrs, n);
 
-	result = createStackTraceElement(name, file);
+        if (addr2line != null)
+          {
+            try
+              {
+                addr2lineOut.write(hex);
+                addr2lineOut.newLine();
+                addr2lineOut.flush();
+                file = addr2lineIn.readLine();
+                int colon = file.lastIndexOf (':');
+                if (colon >= 0 && colon != file.length() - 1)
+                  {
+                    line = Integer.parseInt (file.substring (colon + 1));
+                    file = file.substring (0, colon);
+                  }
+              }
+            catch (IOException ioe) { addr2line = null; }
+            catch (NumberFormatException nfe) { line = -1; }
+          }
+        if (file != null)
+          info = new DebugInfo (file, line);
       }
 
+    if (info != null)
+      result = newElement(info.getFileName(), info.getLineNumber(),
+                          classname, method, nat);
+    else
+      result = newElement(null, -1, classname, method, nat);
+
     return result;
   }
 
@@ -248,7 +244,7 @@
 
     StackTraceElement[] elements = new StackTraceElement[length];
     for (int i=0; i < length; i++)
-      elements[i] = lookup(addrs, i);
+      elements[i] = lookup(addrs, i, trace);
 
     if (demangle && sanitize)
       return sanitizeStack(elements, t);
@@ -256,7 +252,7 @@
       return elements;
   }
 
-  
+
   /**
    * Removes calls to initialize exceptions and the runtime system from
    * the stack trace including stack frames of which nothing usefull is known.
@@ -267,7 +263,7 @@
    * _Jv_Throw call.
    */
   private static StackTraceElement[] sanitizeStack(StackTraceElement[] elements,
-						   Throwable t)
+                                                   Throwable t)
   {
     StackTraceElement[] stack;
 
@@ -286,37 +282,36 @@
     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")
-		|| CName.equals("java.lang.VMThrowable"))
-	    && MName != null
-	    && (MName.startsWith(consName)
-		|| MName.startsWith("Throwable(")
-		|| MName.startsWith("fillInStackTrace("))))
-	  {
-	    last_throw = i;
-	    // Reset counting of unknown and interpreter frames.
-	    unknown = 0;
-	    interpreter = 0;
-	  }
-	else if (remove_unknown && CName == null 
-		 && (MName == null || MName.startsWith("0x")))
-	  unknown++;
-	else if (remove_interpreter
-		 && ((CName == null
-		      && MName != null && MName.startsWith("ffi_"))
-		     || (CName != null && CName.equals("_Jv_InterpMethod"))))
-	  interpreter++;
-	else if ("main(java.lang.String[])".equals(MName))
-	  {
-	    end = i;
-	    break;
-	  }
+        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")
+                || CName.equals("java.lang.VMThrowable"))
+            && MName != null
+            && (MName.equals("<init>")
+                || MName.startsWith("fillInStackTrace("))))
+          {
+            last_throw = i;
+            // Reset counting of unknown and interpreter frames.
+            unknown = 0;
+            interpreter = 0;
+          }
+        else if (remove_unknown && CName == null
+                 && (MName == null || MName.startsWith("0x")))
+          unknown++;
+        else if (remove_interpreter
+                 && ((CName == null
+                      && MName != null && MName.startsWith("ffi_"))
+                     || (CName != null && CName.equals("_Jv_InterpMethod"))))
+          interpreter++;
+        else if ("main(java.lang.String[])".equals(MName))
+          {
+            end = i;
+            break;
+          }
       }
     int begin = last_throw+1;
 
@@ -326,28 +321,28 @@
     // Unless that means we filter out all info.
     int nr_elements = end-begin-unknown-interpreter+1;
     if ((begin > 0 || end < length-1 || unknown > 0 || interpreter > 0)
-	&& nr_elements > 0)
+        && nr_elements > 0)
       {
-	stack = new StackTraceElement[nr_elements];
-	int pos =0;
-	for (int i=begin; i<=end; i++)
-	  {
-	    String MName = elements[i].getMethodName();
-	    String CName = elements[i].getClassName();
-	    if (remove_unknown && CName == null 
-		 && (MName == null || MName.startsWith("0x")))
-	      ; // Skip unknown frame
-	    else if (remove_interpreter
-		     && ((CName == null
-			 && MName != null && MName.startsWith("ffi_"))
-			|| (CName != null && CName.equals("_Jv_InterpMethod"))))
-	      ; // Skip interpreter runtime frame
-	    else
-	      {
-		stack[pos] = elements[i];
-		pos++;
-	      }
-	  }
+        stack = new StackTraceElement[nr_elements];
+        int pos =0;
+        for (int i=begin; i<=end; i++)
+          {
+            String MName = elements[i].getMethodName();
+            String CName = elements[i].getClassName();
+            if (remove_unknown && CName == null
+                 && (MName == null || MName.startsWith("0x")))
+              ; // Skip unknown frame
+            else if (remove_interpreter
+                     && ((CName == null
+                         && MName != null && MName.startsWith("ffi_"))
+                        || (CName != null && CName.equals("_Jv_InterpMethod"))))
+              ; // Skip interpreter runtime frame
+            else
+              {
+                stack[pos] = elements[i];
+                pos++;
+              }
+          }
       }
     else
       stack = elements;
@@ -384,42 +379,42 @@
     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());
-	  }
+        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.lastIndexOf(':');
-	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) || "??".equals(fileName))
-	  fileName = null;
-	else if (fileName != null)
-	  {
-	    try
-	      {
-		fileName = new File(fileName).getCanonicalPath();
-	      }
-	    catch (IOException ioe) { /* ignore */ }
-	  }
+        int colon = file.lastIndexOf(':');
+        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) || "??".equals(fileName))
+          fileName = null;
+        else if (fileName != null)
+          {
+            try
+              {
+                fileName = new File(fileName).getCanonicalPath();
+              }
+            catch (IOException ioe) { /* ignore */ }
+          }
       }
 
     return newElement(fileName, line, className, methodName, false);
@@ -431,17 +426,17 @@
    */
   private String demangleName(String s)
   {
-    if (cppfilt != null)
-    {
-      try
-	{
-	  cppfiltOut.write(s);
-	  cppfiltOut.newLine();
-	  cppfiltOut.flush();
-	  return cppfiltIn.readLine();
-	}
-      catch (IOException ioe) { cppfilt.destroy(); cppfilt = null; }
-    }
+//     if (cppfilt != null)
+//     {
+//       try
+//         {
+//           cppfiltOut.write(s);
+//           cppfiltOut.newLine();
+//           cppfiltOut.flush();
+//           return cppfiltIn.readLine();
+//         }
+//       catch (IOException ioe) { cppfilt.destroy(); cppfilt = null; }
+//     }
 
     return s;
   }
@@ -459,23 +454,23 @@
     // Figure out the real method name
     if (m.startsWith("<init>"))
       {
-	String className;
-	int i = cn.lastIndexOf('.');
-	if (i < 0)
-	  className = cn;
-	else
-	  className = cn.substring(i + 1);
-	sb.append(className);
-	index += 7;
+        String className;
+        int i = cn.lastIndexOf('.');
+        if (i < 0)
+          className = cn;
+        else
+          className = cn.substring(i + 1);
+        sb.append(className);
+        index += 7;
       }
     else
       {
-	int i = m.indexOf('(');
-	if (i > 0)
-	  {
-	    sb.append(m.substring(0,i));
-	    index += i + 1;
-	  }
+        int i = m.indexOf('(');
+        if (i > 0)
+          {
+            sb.append(m.substring(0,i));
+            index += i + 1;
+          }
       }
 
     sb.append('(');
@@ -485,65 +480,65 @@
     char c = (index < length) ? m.charAt(index) : ')';
     while (c != ')')
       {
-	String type;
-	switch(c)
-	{
+        String type;
+        switch(c)
+        {
           case 'B':
             type = "byte";
-	    break;
+            break;
           case 'C':
             type = "char";
-	    break;
+            break;
           case 'D':
             type = "double";
-	    break;
+            break;
           case 'F':
             type = "float";
-	    break;
+            break;
           case 'I':
             type = "int";
-	    break;
+            break;
           case 'J':
             type = "long";
-	    break;
+            break;
           case 'S':
             type = "short";
-	    break;
+            break;
           case 'Z':
             type = "boolean";
-	    break;
+            break;
           case 'L':
-	    int i = m.indexOf(';', index);
-	    if (i > 0)
-	      {
-		type = m.substring(index+1, i);
-		index = i;
-	      }
-	    else
-	      type = "<unknown ref>";
-	    break;
+            int i = m.indexOf(';', index);
+            if (i > 0)
+              {
+                type = m.substring(index+1, i);
+                index = i;
+              }
+            else
+              type = "<unknown ref>";
+            break;
           case '[':
-	    type = "";
-	    arrayDepth++;
-	    break;
+            type = "";
+            arrayDepth++;
+            break;
           default:
-	    type = "<unknown " + c + '>';
-	}
-	sb.append(type);
-
-	// Handle arrays
-	if (c != '[' && arrayDepth > 0)
-	  while (arrayDepth > 0)
-	    {
-	      sb.append("[]");
-	      arrayDepth--;
-	    }
-
-	index++;
-	char nc = (index < length) ? m.charAt(index) : ')';
-	if (c != '[' && nc  != ')')
-	  sb.append(", ");
-	c = nc;
+            type = "<unknown " + c + '>';
+        }
+        sb.append(type);
+
+        // Handle arrays
+        if (c != '[' && arrayDepth > 0)
+          while (arrayDepth > 0)
+            {
+              sb.append("[]");
+              arrayDepth--;
+            }
+
+        index++;
+        char nc = (index < length) ? m.charAt(index) : ')';
+        if (c != '[' && nc  != ')')
+          sb.append(", ");
+        c = nc;
       }
 
     // Stop. We are not interested in the return type.
@@ -556,11 +551,11 @@
    */
   public void close()
   {
-    if (cppfilt != null)
-      cppfilt.destroy();
-
     if (addr2line != null)
-      addr2line.destroy();
+      {
+        addr2line.destroy();
+        try { addr2line.waitFor(); } catch (InterruptedException ie) { }
+      }
   }
 
   /**
Index: libjava/gnu/gcj/runtime/StackTrace.java
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/gnu/gcj/runtime/StackTrace.java,v
retrieving revision 1.3
diff -u -r1.3 StackTrace.java
--- libjava/gnu/gcj/runtime/StackTrace.java	2 Oct 2003 07:10:34 -0000	1.3
+++ libjava/gnu/gcj/runtime/StackTrace.java	16 Jul 2004 03:14:46 -0000
@@ -80,11 +80,11 @@
   public StackTrace()
   {
     int n = 64;
-    
+
     do
       {
-	n *= 4;
-	fillInStackTrace(n, 1);
+        n *= 4;
+        fillInStackTrace(n, 1);
       }
     while (len >= n);
   }
@@ -147,7 +147,7 @@
     update();
     synchronized (map)
       {
-	return (MethodRef) map.get (addr);
+        return (MethodRef) map.get (addr);
       }
   }
 
@@ -155,7 +155,7 @@
   {
     return addrs;
   }
-  
+
   private native void fillInStackTrace(int n, int offset);
   protected native void finalize();
 
Index: libjava/gnu/gcj/runtime/natNameFinder.cc
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/gnu/gcj/runtime/natNameFinder.cc,v
retrieving revision 1.6
diff -u -r1.6 natNameFinder.cc
--- libjava/gnu/gcj/runtime/natNameFinder.cc	9 Apr 2004 04:39:24 -0000	1.6
+++ libjava/gnu/gcj/runtime/natNameFinder.cc	16 Jul 2004 03:14:46 -0000
@@ -11,6 +11,10 @@
 /**
  * @author Mark Wielaard (mark@klomp.org)
  * Based on the old name-finder.cc by Andrew Haley <aph@cygnus.com>.
+ *
+ * DWARF-2 reading by Casey Marshall <csm@gnu.org>. ELF info reading
+ * based on elf/sprof.c from glibc-2.3.2, written by Ulrich Drepper
+ * and Copyright (C) 1997-2002, 2003 Free Software Foundation, Inc.
  */
 
 #include <config.h>
@@ -24,12 +28,28 @@
 #include <java/lang/StringBuffer.h>
 #include <java-interp.h>
 
+#include <gnu/gcj/runtime/DebugInfo.h>
 #include <gnu/gcj/runtime/NameFinder.h>
 
 #ifdef HAVE_DLFCN_H
 #include <dlfcn.h>
 #endif
 
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#ifdef HAVE_LINK_H
+#include <link.h>
+
+static int lookup_debug_line(const void *, char *, int *, int *);
+#endif
+
 // On some systems, a prefix is attached to a method name before
 // it is exported as a label. The GCC preprocessor predefines 
 // this prefix as the macro __USER_LABEL_PREFIX__ which expands to
@@ -100,36 +120,39 @@
   return JvNewStringLatin1(hex);
 }
 
-java::lang::StackTraceElement*
+gnu::gcj::runtime::DebugInfo*
 gnu::gcj::runtime::NameFinder::dladdrLookup(RawData* addrs, jint n)
 {
 #if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
   extern char **_Jv_argv;
-  char name[1024];
   char file_name[1024];
   _Jv_frame_info *stack = (_Jv_frame_info *) addrs;
   void* p = stack[n].addr;
   Dl_info dl_info;
+
+#ifdef INTERPRETER
+  // Skip interpreted frames.
+  if (stack[n].interp != NULL)
+    return NULL;
+#endif // INTERPRETER
    
   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));
+       return new gnu::gcj::runtime::DebugInfo
+	 (JvNewStringLatin1 (file_name), -1);
     }
 #endif
   return NULL;
 }
 
-java::lang::StackTraceElement *
+gnu::gcj::runtime::DebugInfo*
 gnu::gcj::runtime::NameFinder::lookupInterp(RawData* addrs, jint n)
 {
 #ifdef INTERPRETER
@@ -137,21 +160,592 @@
   if (stack[n].interp == NULL)
     return NULL;
 
-  _Jv_InterpMethod *meth
-    = reinterpret_cast<_Jv_InterpMethod *> (stack[n].interp);
-  java::lang::StringBuffer *sb = new java::lang::StringBuffer();
-  sb->append(_Jv_NewStringUtf8Const(meth->self->name));
-  sb->append(_Jv_NewStringUtf8Const(meth->self->signature));
   // FIXME: source file name and line number can be found from
   // bytecode debug information.  But currently we don't keep that
   // around.
-  // FIXME: is using the defining class correct here?
-  java::lang::String *className = meth->defining_class->getName();
-  java::lang::String *methodName
-	  = demangleInterpreterMethod(sb->toString(), className);
-  return new java::lang::StackTraceElement(NULL, -1,
-					   className, methodName, false);
+  return NULL;
 #else // INTERPRETER
   return NULL;
 #endif // INTERPRETER
 }
+
+#define MAX_RESOLVE_FILE_LEN 1024
+
+gnu::gcj::runtime::DebugInfo *
+gnu::gcj::runtime::NameFinder::dwarf2Lookup(RawData *addrs, jint n)
+{
+  _Jv_frame_info *stack = (_Jv_frame_info *) addrs;
+  char fname[MAX_RESOLVE_FILE_LEN];
+  int line = -1, column = -1;
+
+#ifdef INTERPRETER
+  // Don't bother with interpreted frames.
+  if (stack[n].interp != NULL)
+    return NULL;
+#endif
+
+#if HAVE_LINK_H
+  if (! lookup_debug_line (stack[n].addr, fname, &line, &column))
+    return new gnu::gcj::runtime::DebugInfo (JvNewStringLatin1 (fname),
+					     line, column);
+#endif
+  return NULL;
+}
+
+
+// DWARF-2 debug_line routines follow.
+#ifdef HAVE_LINK_H
+
+// #define TRACE_DEBUG_LINE 1
+
+#ifdef TRACE_DEBUG_LINE
+#define TRACE(fmt, args...) fprintf (stderr, "%s:%d: " fmt "\n", __FILE__, __LINE__ , ##args)
+#else
+#define TRACE(fmt, args...)
+#endif
+
+/* Line number opcodes (see gcc/dwarf2.h).  */
+enum dwarf_line_number_ops
+{
+  DW_LNS_extended_op = 0,
+  DW_LNS_copy = 1,
+  DW_LNS_advance_pc = 2,
+  DW_LNS_advance_line = 3,
+  DW_LNS_set_file = 4,
+  DW_LNS_set_column = 5,
+  DW_LNS_negate_stmt = 6,
+  DW_LNS_set_basic_block = 7,
+  DW_LNS_const_add_pc = 8,
+  DW_LNS_fixed_advance_pc = 9,
+};
+
+/* Line number extended opcodes.  */
+enum dwarf_line_number_x_ops
+{
+  DW_LNE_end_sequence = 1,
+  DW_LNE_set_address = 2,
+  DW_LNE_define_file = 3
+};
+
+#define read_sbyte(fd,c,d) read (fd, & d, 1); c++
+#define read_ubyte(fd,c,d) read (fd, & d, 1); c++
+#define read_uhalf(fd,c,d) read (fd, & d, 2); c += 2
+#define read_sword(fd,c,d) read (fd, & d, 4); c += 4
+#define read_uword(fd,c,d) read (fd, & d, 4); c += 4
+
+/* see gcc/gcc/unwind-pe.h */
+static int
+read_uleb128 (int fd, unsigned long *val)
+{
+  unsigned int shift = 0;
+  unsigned char byte;
+  unsigned long result;
+  int count = 0;
+
+  result = 0;
+  do
+    {
+      read (fd, &byte, 1);
+      count++;
+      result |= ((unsigned long)byte & 0x7f) << shift;
+      shift += 7;
+    }
+  while (byte & 0x80);
+
+  TRACE("read %d byte uleb128: %lu", count, result);
+
+  if (val)
+    *val = result;
+  return count;
+}
+
+static int
+read_sleb128 (int fd, long *val)
+{
+  unsigned int shift = 0;
+  unsigned char byte;
+  unsigned long result;
+  int count = 0;
+
+  result = 0;
+  do
+    {
+      read (fd, &byte, 1);
+      count++;
+      result |= ((long)byte & 0x7f) << shift;
+      shift += 7;
+    }
+  while (byte & 0x80);
+
+  /* Sign-extend a negative value.  */
+  if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
+    result |= -(((unsigned long)1L) << shift);
+
+  TRACE("read %d byte sleb128: %ld", count, (long) result);
+
+  if (val)
+    *val = (long) result;
+  return count;
+}
+
+static void
+read_string (int fd, char *str, int len, off_t *count)
+{
+  int n = 0;
+  char c;
+
+  do
+    {
+      read (fd, &c, 1);
+      if (str && n < len)
+	str[n] = c;
+      if (str && n >= len)
+	str[len-1] = '\0';
+      n++;
+    }
+  while (c);
+  TRACE("Read %d byte string %s", n, str ? str : "(nil)");
+  if (count)
+    *count += n;
+}
+
+#define MAX_FNAMES 128
+
+/*
+ * Interpret the DWARF-2 debug line section, stopping when we find
+ * a file name and line number for the address ADDR. The file name
+ * (if found) will be stored in FILE, which must have MAX_RESOLVE_FILE_LEN
+ * bytes available, and the line and column numbers will be stored in
+ * LINE and COLUMN.
+ *
+ * FD should point to the opened shared library, and should be positioned
+ * to the beginning of the .debug_line section.
+ */
+static int
+interpret_dw2 (int fd, off_t len, const void *addr,
+	       char *file, int *line, int *column)
+{
+  char *address;
+  off_t count = 0;
+  uint8_t min_insn_len;
+  int8_t line_base;
+  uint32_t entry_len, prologue_len;
+  off_t entry_end, prologue_end;
+  uint8_t line_range;
+  uint8_t opcode_base;
+
+  /* We assume here that we are not going to read anything more than
+     DWARF-2, and thus don't need anything more than an opcode_base of
+     10. */
+  uint8_t opcode_args[9];
+
+  /* There can be more than 128 names in a section, but we will assume
+     that there aren't (we don't want to malloc anything here). */
+  off_t fnames[MAX_FNAMES];
+  int n_fnames = 0;
+  int i, const_add;
+  uint16_t version;
+  uint8_t isstmt;
+  unsigned long fileno;
+  int found = 0;
+  char c1, c2;
+  off_t define_file = 0;
+
+  TRACE("looking for %p...", addr);
+
+  while (count < len)
+    {
+      read_uword (fd, count, entry_len);
+      entry_end = count + entry_len;
+      read_uhalf (fd, count, version);
+      if (version != 2)
+	{
+	  TRACE("skipping unsupported version %d", version);
+	  lseek (fd, entry_len - 2, SEEK_CUR);
+	  count += entry_len - 2;
+	  continue;
+	}
+      read_uword (fd, count, prologue_len);
+      prologue_end = count + prologue_len;
+      read_ubyte (fd, count, min_insn_len);
+      read_ubyte (fd, count, isstmt);
+      read_sbyte (fd, count, line_base);
+      read_ubyte (fd, count, line_range);
+      read_ubyte (fd, count, opcode_base);
+      if (opcode_base != 10)
+	{
+	  TRACE("skipping section with opcode_base=%d", opcode_base);
+	  lseek (fd, entry_end - count, SEEK_CUR);
+	  count = entry_end;
+	  continue;
+	}
+      read (fd, opcode_args, 9);
+      count += 9;
+      const_add = 255 / line_range;
+
+      TRACE("length:          %d", entry_len);
+      TRACE("version:         %d", version);
+      TRACE("prologue length: %d", prologue_len);
+      TRACE("min_insn_len:    %d", min_insn_len);
+      TRACE("is-statement:    %d", isstmt);
+      TRACE("line_base:       %d", line_base);
+      TRACE("line_range:      %d", line_range);
+      TRACE("opcode base:     %d", opcode_base);
+      TRACE("count=%d entry_end=%d prologue_end=%d", count, entry_end, prologue_end);
+
+      /* Skip through the include directories. We won't use them. */
+      read_ubyte (fd, count, c1);
+      c2 = 'x';
+      if (c1)
+	while (!(c1 == '\0' && c2 == '\0'))
+	  {
+	    c2 = c1;
+	    read_ubyte (fd, count, c1);
+	  }
+      n_fnames = 0;
+      while (count < prologue_end - 1)
+	{
+	  /* Skip the file name, but remember where it is. */
+	  if (n_fnames < MAX_FNAMES)
+	    fnames[n_fnames++] = lseek (fd, 0, SEEK_CUR);
+	  read_string (fd, NULL, 0, &count);
+
+	  /* We don't use the directories or file attributes. */
+	  count += read_uleb128 (fd, NULL);
+	  count += read_uleb128 (fd, NULL);
+	  count += read_uleb128 (fd, NULL);
+	}
+      read_ubyte (fd, count, c1);
+
+      address = NULL;
+      fileno = 1;
+      *line = 1;
+      *column = 0;
+
+      while (count < entry_end)
+	{
+	  uint8_t opcode;
+	  read_ubyte (fd, count, opcode);
+	  TRACE("read opcode %02x", opcode);
+	  if (opcode < opcode_base)
+	    switch (opcode)
+	      {
+	      case DW_LNS_extended_op:
+		{
+		  unsigned long insn_len;
+		  count += read_uleb128 (fd, &insn_len);
+		  read_ubyte (fd, count, opcode);
+		  TRACE("read extended opcode %02x", opcode);
+		  switch (opcode)
+		    {
+		    case DW_LNE_end_sequence:
+		      TRACE("End of sequence");
+		      break;
+
+		    case DW_LNE_set_address:
+		      read (fd, &address, sizeof (void *));
+		      count += sizeof (void *);
+		      TRACE("Set address to %p", address);
+		      if (address > addr)
+			{
+			  lseek (fd, entry_end - count, SEEK_CUR);
+			  count = entry_end;
+			  continue;
+			}
+		      break;
+
+		    case DW_LNE_define_file:
+		      {
+			define_file = lseek (fd, 0, SEEK_CUR);
+			read_string (fd, NULL, 0, &count);
+			count += read_uleb128 (fd, NULL);
+			count += read_uleb128 (fd, NULL);
+			count += read_uleb128 (fd, NULL);
+		      }
+		      break;
+
+		    default:
+		      TRACE("Unsupported extended opcode %d", opcode);
+		      lseek (fd, insn_len, SEEK_CUR);
+		      count += insn_len;
+		    }
+		}
+		break;
+
+	      case DW_LNS_copy:
+		TRACE("Copy (ignored)");
+		break;
+
+	      case DW_LNS_advance_pc:
+		{
+		  unsigned long amt = 0;
+		  count += read_uleb128 (fd, &amt);
+		  address += amt * min_insn_len;
+		  TRACE("Advance PC by %lu to %p", amt, address);
+		  if (address > addr)
+		    {
+		      found = 1;
+		      goto finished;
+		    }
+		}
+		break;
+
+	      case DW_LNS_advance_line:
+		{
+		  long amt = 0;
+		  count += read_sleb128 (fd, &amt);
+		  *line += (int) amt;
+		  TRACE("Advance line by %ld to %d", amt, *line);
+		}
+		break;
+
+	      case DW_LNS_set_file:
+		{
+		  unsigned long idx = 0;
+		  count += read_uleb128 (fd, &idx);
+		  fileno = idx;
+		  TRACE("Set file to %d", idx);
+		}
+		break;
+
+	      case DW_LNS_set_column:
+		{
+		  unsigned long amt = 0;
+		  count += read_uleb128 (fd, &amt);
+		  *column = amt;
+		  TRACE("Set column to %d", amt);
+		}
+		break;
+
+	      case DW_LNS_negate_stmt:
+		TRACE("Negate statement (ignored)");
+		break;
+
+	      case DW_LNS_set_basic_block:
+		TRACE("Set basic block (ignored)");
+		break;
+
+	      case DW_LNS_const_add_pc:
+		address += const_add;
+		TRACE("Advance PC by (constant) %d to %p", const_add, address);
+		if (address > addr)
+		  {
+		    found = 1;
+		    goto finished;
+		  }
+		break;
+
+	      case DW_LNS_fixed_advance_pc:
+		{
+		  uint16_t amt;
+		  read_uhalf (fd, count, amt);
+		  address += amt;
+		  TRACE("Advance PC by (fixed) %d to %p", amt, address);
+		  if (address > addr)
+		    {
+		      found = 1;
+		      goto finished;
+		    }
+		}
+		break;
+
+	      default:
+		TRACE("Ignoring unsupported opcode: %d", opcode);
+		for (i = 0; i < opcode_args[opcode-1]; i++)
+		  count += read_uleb128 (fd, NULL);
+		break;
+	      }
+	  else // special opcode
+	    {
+	      int adj = opcode - opcode_base;
+	      int line_adv = line_base + (adj % line_range);
+	      int addr_adv = adj / line_range;
+	      *line += line_adv;
+	      address += addr_adv;
+	      TRACE("Special opcode %d advance line by %d to %d and addr by %d to %p",
+		    opcode, *line, line_adv, addr_adv, address);
+	      if (address > addr)
+		{
+		  found = 1;
+		  goto finished;
+		}
+	    }
+	}
+    }
+
+ finished:
+  if (found)
+    {
+      if (fileno == 0 && define_file != 0)
+	{
+	  lseek (fd, define_file, SEEK_SET);
+	  read_string (fd, file, MAX_RESOLVE_FILE_LEN, NULL);
+	}
+      for (i = 1; i <= fileno && i < n_fnames; i++)
+	if (i == fileno)
+	  {
+	    lseek (fd, fnames[i-1], SEEK_SET);
+	    read_string (fd, file, MAX_RESOLVE_FILE_LEN, NULL);
+	  }
+      return 0;
+    }
+  return 1;
+}
+
+/*
+ * Read and interpret the debugging information for ADDR, if present.
+ * The file, line, and column numbers will be stored in FILE, LINE, and
+ * COLUMN. FILE should point to at least MAX_RESOLVE_FILE_LEN bytes.
+ */
+static int
+lookup_debug_line (const void *addr, char *file, int *line, int *column)
+{
+  void *ptr;
+  struct r_debug *rdbg = NULL;
+  ElfW(Dyn) *dyn;
+  ElfW(Ehdr) *ehdr;
+  ElfW(Shdr) *shdr;
+  ElfW(Shdr) *debug_line;
+  ElfW(Addr) base_addr;
+  const char *shstrtab;
+  size_t debug_line_sz;
+  struct link_map *lmap;
+  struct link_map *base = NULL;
+  int fd, i;
+  const int pagesize = sysconf (_SC_PAGESIZE);
+
+  TRACE("pagesize is %d", pagesize);
+  TRACE("reading info for pc=%p", addr);
+
+  for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn)
+    if (dyn->d_tag == DT_DEBUG)
+      {
+	rdbg = (struct r_debug *) dyn->d_un.d_ptr;
+	break;
+      }
+  if (!rdbg)
+    rdbg = &_r_debug;
+
+  for (lmap = rdbg->r_map; lmap != NULL; lmap = lmap->l_next)
+    {
+      TRACE("looking at %p", lmap->l_addr);
+      if (lmap->l_addr && addr > (void *) lmap->l_addr)
+	{
+	  if (!base || lmap->l_addr > base->l_addr)
+	    base = lmap;
+	}
+    }
+  if (!base || !base->l_addr)
+    {
+      TRACE("no dynamic info found");
+      return 1;
+    }
+  TRACE("found base address=%p", base->l_addr);
+
+  if (!base->l_name || !*(base->l_name))
+    {
+      TRACE("no library file name");
+      return 1;
+    }
+  TRACE("reading shared library %s...", base->l_name);
+  ehdr = (ElfW(Ehdr) *) base->l_addr;
+
+  fd = open (base->l_name, O_RDONLY);
+  if (fd < 0)
+    {
+      TRACE("open %s failed: %s", base->l_name, strerror (errno));
+      return 1;
+    }
+
+  base_addr = base->l_addr;
+  base = NULL;
+  lmap = NULL;
+
+  /* Load the section header table. */
+  TRACE("mapping section headers len=%ld adj=%ld off=%ld offa=%ld",
+	ehdr->e_shnum * sizeof (ElfW(Shdr)),
+	ehdr->e_shoff & (pagesize - 1),
+	ehdr->e_shoff,
+	ehdr->e_shoff & ~(pagesize - 1));
+  ptr = mmap (NULL, (ehdr->e_shnum * sizeof (ElfW(Shdr))
+		     + (ehdr->e_shoff & (pagesize - 1))), PROT_READ,
+	      MAP_SHARED|MAP_FILE, fd, ehdr->e_shoff & ~(pagesize - 1));
+  if (ptr == MAP_FAILED)
+    {
+      TRACE("mmap sections failed: %s", strerror (errno));
+      close (fd);
+      return 1;
+    }
+  shdr = (ElfW(Shdr) *) ((char *) ptr
+			 + (ehdr->e_shoff & (pagesize - 1)));
+
+  TRACE("shdr[ehdr->e_shstrndx].sh_type=%d", shdr[ehdr->e_shstrndx].sh_type);
+
+  /* Load the string table. */
+  TRACE("mapping string table size=%ld adj=%ld off=%ld offa=%ld",
+	shdr[ehdr->e_shstrndx].sh_size,
+	(shdr[ehdr->e_shstrndx].sh_offset & (pagesize - 1)),
+	shdr[ehdr->e_shstrndx].sh_offset,
+	(shdr[ehdr->e_shstrndx].sh_offset & ~(pagesize - 1)));
+
+  ptr = mmap (NULL, (shdr[ehdr->e_shstrndx].sh_size
+		     + (shdr[ehdr->e_shstrndx].sh_offset & (pagesize - 1))),
+	      PROT_READ, MAP_SHARED|MAP_FILE, fd,
+	      shdr[ehdr->e_shstrndx].sh_offset & ~(pagesize - 1));
+  if (ptr == MAP_FAILED)
+    {
+      TRACE("mmap string table failed: %s", strerror (errno));
+      munmap (shdr - (ehdr->e_shoff & (pagesize - 1)),
+	      (ehdr->e_phnum * sizeof (ElfW(Shdr))
+	       + (ehdr->e_shoff & ~(pagesize - 1))));
+      return 1;
+    }
+  shstrtab = ((const char *) ptr
+	      + (shdr[ehdr->e_shstrndx].sh_offset & (pagesize - 1)));
+  TRACE("I think the string table is at %p", shstrtab);
+
+  // find the .debug_line section.
+  debug_line = NULL;
+  for (i = 0; i < ehdr->e_shnum; i++)
+    {
+      TRACE("checking %d %d", i, shdr[i].sh_name);
+      TRACE("sh_name=%s", shstrtab + shdr[i].sh_name);
+      if (strcmp (shstrtab + shdr[i].sh_name, ".debug_line") == 0)
+	{
+	  debug_line = &shdr[i];
+	  break;
+	}
+    }
+  TRACE("found .debug_line header section header at %p", debug_line);
+
+  munmap (ptr, (shdr[ehdr->e_shstrndx].sh_size
+		+ (shdr[ehdr->e_shstrndx].sh_offset & (pagesize - 1))));
+
+  /* Quit if there is no .debug_line section. */
+  if (debug_line == NULL)
+    {
+      TRACE("no .debug_line section found");
+      munmap ((char *) shdr - (ehdr->e_shoff & (pagesize - 1)),
+	      (ehdr->e_phnum * sizeof (ElfW(Shdr))
+	       + (ehdr->e_shoff & (pagesize - 1))));
+      close (fd);
+      return 1;
+    }
+
+  /* Move to the beginning of the section, then pass it off to the
+     interpreter. */
+  lseek (fd, debug_line->sh_offset, SEEK_SET);
+  debug_line_sz = debug_line->sh_size;
+  munmap (shdr - (ehdr->e_shoff & (pagesize - 1)),
+	  (ehdr->e_phnum * sizeof (ElfW(Shdr))
+	   + (ehdr->e_shoff & (pagesize - 1))));
+
+  int ret = interpret_dw2 (fd, debug_line_sz,
+			   (void *) ((char *) addr - base_addr),
+			   file, line, column);
+
+  close (fd);
+  return ret;
+}
+
+#endif // HAVE_LINK_H
Index: libjava/include/config.h.in
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/include/config.h.in,v
retrieving revision 1.52
diff -u -r1.52 config.h.in
--- libjava/include/config.h.in	2 Dec 2003 22:26:49 -0000	1.52
+++ libjava/include/config.h.in	16 Jul 2004 03:14:46 -0000
@@ -200,6 +200,9 @@
 /* Define if you have the <dlfcn.h> header file.  */
 #undef HAVE_DLFCN_H
 
+/* Define if you have the <elf.h> header file.  */
+#undef HAVE_ELF_H
+
 /* Define if you have the <execinfo.h> header file.  */
 #undef HAVE_EXECINFO_H
 
@@ -212,6 +215,9 @@
 /* Define if you have the <langinfo.h> header file.  */
 #undef HAVE_LANGINFO_H
 
+/* Define if you have the <link.h> header file.  */
+#undef HAVE_LINK_H
+
 /* Define if you have the <locale.h> header file.  */
 #undef HAVE_LOCALE_H
 

Attachment: DebugInfo.java
Description: Text document


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