1 /* NameFinder.java -- Translates addresses to StackTraceElements.
2 Copyright (C) 2002, 2004 Free Software Foundation, Inc.
4 This file is part of libgcj.
6 This software is copyrighted work licensed under the terms of the
7 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
10 package gnu.gcj.runtime;
12 import gnu.classpath.Configuration;
13 import gnu.gcj.RawData;
15 import java.lang.StringBuffer;
17 import java.io.BufferedReader;
18 import java.io.BufferedWriter;
19 import java.io.InputStreamReader;
20 import java.io.OutputStreamWriter;
21 import java.io.IOException;
23 import java.util.Iterator;
24 import java.util.HashMap;
28 * Lookup addresses (represented as longs) to find source & line number info.
30 * The following system property is available (defaults to true):
32 * <ul><code>gnu.gcj.runtime.NameFinder.use_addr2line</code>
33 * Whether an external process, addr2line, should be used to look up
34 * source file and line number info. Throwable.printStackTrace() will
35 * be faster if this property is set to 'false'.
37 * <ul><code>gnu.gcj.runtime.NameFinder.remove_unknown</code>
38 * Whether calls to unknown functions (class and method names are unknown)
39 * should be removed from the stack trace. </ul>
42 * <code>close()</code> should be called to get rid of all resources.
44 * This class is used from <code>java.lang.VMThrowable</code>.
46 * @author Mark Wielaard (mark@klomp.org)
48 public class NameFinder
51 * The name of the binary to look up.
53 private String binaryFile;
54 private String sourceFile;
56 private HashMap procs = new HashMap();
58 private static final boolean use_addr2line
59 = Boolean.valueOf(System.getProperty
60 ("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
63 private static final boolean remove_unknown
64 = Boolean.valueOf(System.getProperty
65 ("gnu.gcj.runtime.NameFinder.remove_unknown", "true")
68 // Return true if non-Java frames should be removed from stack
70 static final boolean removeUnknown()
72 return remove_unknown;
81 Addr2Line(String binaryFile)
85 String[] exec = new String[] {"addr2line", "-e", binaryFile};
86 Runtime runtime = Runtime.getRuntime();
87 proc = runtime.exec(exec);
89 catch (IOException ioe)
95 in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
96 out = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
109 catch (IOException x) {}
116 * Create a new NameFinder to lookup names in binaryFile. Call close to get rid of any
117 * resources created while using the <code>lookup</code> methods.
124 * Returns the source file name if lookup() was successful. If the source file could not be
125 * determined, the binary name will be returned instead.
127 public String getSourceFile()
130 if (sourceFile != null)
135 return file.substring(file.lastIndexOf(File.separator) + 1, file.length());
139 * If lookup() was successful, returns the line number of addr. If the line number could not
140 * be determined, -1 is returned.
142 public int getLineNum()
147 public void lookup (String file, long addr)
155 Addr2Line addr2line = (Addr2Line) procs.get(file);
156 if (addr2line == null)
158 addr2line = new Addr2Line(file);
159 procs.put(file, addr2line);
162 if (addr2line.proc == null)
165 String hexAddr = "0x" + Long.toHexString(addr);
170 addr2line.out.write(hexAddr);
171 addr2line.out.newLine();
172 addr2line.out.flush();
173 String result = addr2line.in.readLine();
175 if (result.indexOf("??") == -1)
177 int split = result.lastIndexOf(':');
178 sourceFile = result.substring(0, split);
179 String lineNumStr = result.substring(split + 1, result.length());
180 lineNum = Integer.parseInt (lineNumStr);
183 catch (IOException ioe)
187 catch (NumberFormatException x)
193 * Returns human readable method name and aguments given a method type
194 * signature as known to the interpreter and a classname.
196 public static String demangleInterpreterMethod(String m, String cn)
199 int length = m.length();
200 StringBuffer sb = new StringBuffer(length);
202 // Figure out the real method name
203 if (m.startsWith("<init>"))
206 int i = cn.lastIndexOf('.');
210 className = cn.substring(i + 1);
211 sb.append(className);
216 int i = m.indexOf('(');
219 sb.append(m.substring(0,i));
226 // Demangle the type arguments
228 char c = (index < length) ? m.charAt(index) : ')';
259 int i = m.indexOf(';', index);
262 type = m.substring(index+1, i);
266 type = "<unknown ref>";
273 type = "<unknown " + c + '>';
278 if (c != '[' && arrayDepth > 0)
279 while (arrayDepth > 0)
286 char nc = (index < length) ? m.charAt(index) : ')';
287 if (c != '[' && nc != ')')
292 // Stop. We are not interested in the return type.
294 return sb.toString();
298 * Releases all resources used by this NameFinder.
302 Iterator itr = procs.values().iterator();
303 while (itr.hasNext())
305 Addr2Line proc = (Addr2Line) itr.next();