18744d9b72
2005-03-10 Bryce McKinlay <mckinlay@redhat.com> New Stack Trace infrastructure. * Makefile.am (libgcj0_convenience_la_SOURCES): Add stacktrace.cc. (gnu/gcj/runtime/StackTrace.lo): Removed. (ordinary_java_source_files): Remove obsolete files. (nat_source_files): Remove obsolete files. Add natVMThrowable.cc. * configure.host (fallback_backtrace_h): Set backtrace header for mingw and cygwin targets. * configure.ac: Make symlink for fallback backtrace headers. * Makefile.in, configure: Rebuilt. * defineclass.cc (_Jv_ClassReader::read_one_code_attribute): Read 'LineNumberTable' attribute. (_Jv_ClassReader::read_one_class_attribute): Read 'SourceFile' attribute. (_Jv_ClassReader::handleCodeAttribute): Initialize method line table fields. * exception.cc: Remove unused include. * interpret.cc (DIRECT_THREADED, insn_slot): Moved to java-interp.h. (SAVE_PC): New macro. Save current PC in the interpreter frame. (NULLCHECK, NULLARRAYCHECK): Use SAVE_PC. (_Jv_InterpMethod::compile): Translate bytecode PC values in the line table to direct threaded instruction values. (_Jv_StartOfInterpreter, _Jv_EndOfInterpreter): Removed. (_Jv_InterpMethod::run): No longer member function. All callers updated. Remove _Unwind calls. Call SAVE_PC whenever a call is made or where an instruction could throw. (_Jv_InterpMethod::get_source_line): New. Look up source line numbers in line_table. * prims.cc (catch_segv): Construct exception after MAKE_THROW_FRAME. (catch_fpe): Likewise. * stacktrace.cc: New file. Stack trace code now here. * gnu/gcj/runtime/MethodRef.java: * gnu/gcj/runtime/NameFinder.java: Mostly reimplemented. Now simply calls addr2line to look up PC addresses in a given binary or shared library. * gnu/gcj/runtime/StackTrace.java, gnu/gcj/runtime/natNameFinder.cc, gnu/gcj/runtime/natStackTrace.cc: Removed. * gnu/java/lang/MainThread.java (call_main): Add comment warning that this function name is specially recognised by the stack trace code and shouldn't be changed. * include/java-interp.h (DIRECT_THREADED, insn_slot): Moved here. (struct _Jv_LineTableEntry, line_table, line_table_len): New. (_Jv_InterpMethod::run): Update declaration. (_Jv_StackTrace_): New friend. NameFinder and StackTrace no longer friends. (_Jv_InterpFrame): Renamed from _Jv_MethodChain. Add PC field. * include/java-stack.h: New file. Declarations for stack tracing. * include/jvm.h (_Jv_Frame_info): Removed. * java/lang/Class.h: Update friend declarations. * java/lang/VMClassLoader.java (getSystemClassLoader): Simplify exception message. * java/lang/VMThrowable.java (fillInStackTrace): Now native. (getStackTrace): Now native. (data): New RawDataManaged field. * java/lang/natClass.cc: Update includes. (forName): Use _Jv_StackTrace::GetCallingClass for calling-classloader check. (getClassLoader): Likewise. * java/lang/natRuntime.cc: Update includes. (_load): Use _Jv_StackTrace::GetFirstNonSystemClassLoader. * java/lang/natVMSecurityManager.cc: Update includes. (getClassContext): Use _Jv_StackTrace::GetClassContext. * java/lang/natVMThrowable.cc: New file. Native methods for VMThrowable. * java/lang/reflect/natArray.cc: Update includes. (newInstance): Use _Jv_StackTrace::GetCallingClass to implement accessibility check. * java/lang/reflect/natConstructor.cc: Update includes. (newInstance): Use _Jv_StackTrace::GetCallingClass to implement accessibility check. * java/lang/reflect/natField.cc: Update includes. (getAddr): Use _Jv_StackTrace::GetCallingClass to implement accessibility check. * java/lang/reflect/natMethod.cc: Update includes. (invoke): Use _Jv_StackTrace::GetCallingClass to implement accessibility check. * java/util/natResourceBundle.cc: Update includes. (getCallingClassLoader): Use _Jv_StackTrace::GetCallingClass. * java/util/logging/natLogger.cc: Update includes. Use _Jv_StackTrace::GetCallerInfo to get call-site info. * sysdep/generic/backtrace.h: Fallback backtrace code. Stub implementation. * sysdep/i386/backtrace.h: New. Fallback backtrace code. i386 implementation. From-SVN: r96253
293 lines
6.3 KiB
Java
293 lines
6.3 KiB
Java
/* NameFinder.java -- Translates addresses to StackTraceElements.
|
|
Copyright (C) 2002, 2004 Free Software Foundation, Inc.
|
|
|
|
This file is part of libgcj.
|
|
|
|
This software is copyrighted work licensed under the terms of the
|
|
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
|
details. */
|
|
|
|
package gnu.gcj.runtime;
|
|
|
|
import gnu.classpath.Configuration;
|
|
import gnu.gcj.RawData;
|
|
|
|
import java.lang.StringBuffer;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.BufferedWriter;
|
|
import java.io.InputStreamReader;
|
|
import java.io.OutputStreamWriter;
|
|
import java.io.IOException;
|
|
import java.io.File;
|
|
import java.util.Iterator;
|
|
import java.util.HashMap;
|
|
|
|
|
|
/**
|
|
* Lookup addresses (represented as longs) to find source & line number info.
|
|
*
|
|
* The following system property is available (defaults to true):
|
|
* <li>
|
|
* <ul><code>gnu.gcj.runtime.NameFinder.use_addr2line</code>
|
|
* Whether an external process, addr2line, should be used to look up
|
|
* source file and line number info. Throwable.printStackTrace() will
|
|
* be faster if this property is set to 'false'.
|
|
* </ul>
|
|
* </li>
|
|
*
|
|
* <code>close()</code> should be called to get rid of all resources.
|
|
*
|
|
* This class is used from <code>java.lang.VMThrowable</code>.
|
|
*
|
|
* @author Mark Wielaard (mark@klomp.org)
|
|
*/
|
|
public class NameFinder
|
|
{
|
|
/**
|
|
* The name of the binary to look up.
|
|
*/
|
|
private String binaryFile;
|
|
private String sourceFile;
|
|
private int lineNum;
|
|
private HashMap procs = new HashMap();
|
|
|
|
private static final boolean use_addr2line
|
|
= Boolean.valueOf(System.getProperty
|
|
("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
|
|
).booleanValue();
|
|
|
|
class Addr2Line
|
|
{
|
|
Process proc;
|
|
BufferedWriter out;
|
|
BufferedReader in;
|
|
|
|
Addr2Line(String binaryFile)
|
|
{
|
|
try
|
|
{
|
|
String[] exec = new String[] {"addr2line", "-e", binaryFile};
|
|
Runtime runtime = Runtime.getRuntime();
|
|
proc = runtime.exec(exec);
|
|
}
|
|
catch (IOException ioe)
|
|
{
|
|
}
|
|
|
|
if (proc != null)
|
|
{
|
|
in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
|
|
out = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
|
|
}
|
|
}
|
|
|
|
void close()
|
|
{
|
|
try
|
|
{
|
|
in.close();
|
|
out.close();
|
|
}
|
|
catch (IOException x) {}
|
|
|
|
proc.destroy();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a new NameFinder to lookup names in binaryFile. Call close to get rid of any
|
|
* resources created while using the <code>lookup</code> methods.
|
|
*/
|
|
public NameFinder()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Returns the source file name if lookup() was successful. If the source file could not be
|
|
* determined, the binary name will be returned instead.
|
|
*/
|
|
public String getSourceFile()
|
|
{
|
|
String file;
|
|
if (sourceFile != null)
|
|
file = sourceFile;
|
|
else
|
|
file = binaryFile;
|
|
|
|
return file.substring(file.lastIndexOf(File.separator) + 1, file.length());
|
|
}
|
|
|
|
/**
|
|
* If lookup() was successful, returns the line number of addr. If the line number could not
|
|
* be determined, -1 is returned.
|
|
*/
|
|
public int getLineNum()
|
|
{
|
|
return lineNum;
|
|
}
|
|
|
|
public void lookup (String file, long addr)
|
|
{
|
|
binaryFile = file;
|
|
sourceFile = null;
|
|
lineNum = -1;
|
|
|
|
if (! use_addr2line)
|
|
return;
|
|
Addr2Line addr2line = (Addr2Line) procs.get(file);
|
|
if (addr2line == null)
|
|
{
|
|
addr2line = new Addr2Line(file);
|
|
procs.put(file, addr2line);
|
|
}
|
|
|
|
if (addr2line.proc == null)
|
|
return;
|
|
|
|
String hexAddr = "0x" + Long.toHexString(addr);
|
|
String name;
|
|
|
|
try
|
|
{
|
|
addr2line.out.write(hexAddr);
|
|
addr2line.out.newLine();
|
|
addr2line.out.flush();
|
|
String result = addr2line.in.readLine();
|
|
|
|
if (result.indexOf("??") == -1)
|
|
{
|
|
int split = result.lastIndexOf(':');
|
|
sourceFile = result.substring(0, split);
|
|
String lineNumStr = result.substring(split + 1, result.length());
|
|
lineNum = Integer.parseInt (lineNumStr);
|
|
}
|
|
}
|
|
catch (IOException ioe)
|
|
{
|
|
addr2line = null;
|
|
}
|
|
catch (NumberFormatException x)
|
|
{
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns human readable method name and aguments given a method type
|
|
* signature as known to the interpreter and a classname.
|
|
*/
|
|
public static String demangleInterpreterMethod(String m, String cn)
|
|
{
|
|
int index = 0;
|
|
int length = m.length();
|
|
StringBuffer sb = new StringBuffer(length);
|
|
|
|
// 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;
|
|
}
|
|
else
|
|
{
|
|
int i = m.indexOf('(');
|
|
if (i > 0)
|
|
{
|
|
sb.append(m.substring(0,i));
|
|
index += i + 1;
|
|
}
|
|
}
|
|
|
|
sb.append('(');
|
|
|
|
// Demangle the type arguments
|
|
int arrayDepth = 0;
|
|
char c = (index < length) ? m.charAt(index) : ')';
|
|
while (c != ')')
|
|
{
|
|
String type;
|
|
switch(c)
|
|
{
|
|
case 'B':
|
|
type = "byte";
|
|
break;
|
|
case 'C':
|
|
type = "char";
|
|
break;
|
|
case 'D':
|
|
type = "double";
|
|
break;
|
|
case 'F':
|
|
type = "float";
|
|
break;
|
|
case 'I':
|
|
type = "int";
|
|
break;
|
|
case 'J':
|
|
type = "long";
|
|
break;
|
|
case 'S':
|
|
type = "short";
|
|
break;
|
|
case 'Z':
|
|
type = "boolean";
|
|
break;
|
|
case 'L':
|
|
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;
|
|
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;
|
|
}
|
|
|
|
// Stop. We are not interested in the return type.
|
|
sb.append(')');
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Releases all resources used by this NameFinder.
|
|
*/
|
|
public void close()
|
|
{
|
|
Iterator itr = procs.values().iterator();
|
|
while (itr.hasNext())
|
|
{
|
|
Addr2Line proc = (Addr2Line) itr.next();
|
|
proc.close();
|
|
}
|
|
}
|
|
}
|