199 lines
5.4 KiB
Java
199 lines
5.4 KiB
Java
/* SymbolTable.java -- Maintains a mapping of addresses to names.
|
|
Copyright (C) 2007 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 gnu.gcj.tools.gc_analyze;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.InputStreamReader;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
class SymbolTable
|
|
{
|
|
// Long address->String name
|
|
private HashMap<Long, String> map = new HashMap<Long, String>();
|
|
|
|
// Reverse
|
|
// String name -> Long address
|
|
// used for RelocateImage
|
|
private HashMap<String, Long> reverse = new HashMap<String, Long>();
|
|
|
|
long loadAddr;
|
|
long relocation;
|
|
|
|
static Matcher interestingSymbol =
|
|
Pattern.compile("^([0-9a-fA-F]+)\\s+\\S+\\s+(_Z\\S+)").matcher("");
|
|
static Matcher readelfLoadMatcher =
|
|
Pattern.compile("^\\s+LOAD\\s+(\\S+)\\s+(\\S+)\\s.*").matcher("");
|
|
|
|
public SymbolTable(String filename) throws IOException
|
|
{
|
|
Process p = Runtime.getRuntime().exec(ToolPrefix.toolPrefix
|
|
+ "nm " + filename);
|
|
InputStream es = p.getErrorStream();
|
|
InputStream is = p.getInputStream();
|
|
|
|
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
|
int count = 0;
|
|
|
|
String line;
|
|
while ((line = reader.readLine()) != null)
|
|
{
|
|
interestingSymbol.reset(line);
|
|
if (interestingSymbol.matches())
|
|
{
|
|
try
|
|
{
|
|
String name = interestingSymbol.group(2);
|
|
String addr = interestingSymbol.group(1);
|
|
if (name.startsWith("_ZTVN") || name.endsWith("6class$E"))
|
|
{
|
|
long address = MemoryMap.parseHexLong(addr);
|
|
Long l = new Long(address);
|
|
map.put(l, name);
|
|
count++;
|
|
reverse.put(name, l);
|
|
}
|
|
}
|
|
catch (NumberFormatException e)
|
|
{
|
|
// ignore it
|
|
}
|
|
}
|
|
}
|
|
es.close();
|
|
is.close();
|
|
p.destroy();
|
|
|
|
if (count > 0)
|
|
{
|
|
// Assume nm read some symbols from it and that
|
|
// readelf can tell us something about how it is loaded.
|
|
p = Runtime.getRuntime().exec(ToolPrefix.toolPrefix
|
|
+ "readelf -l " + filename);
|
|
es = p.getErrorStream();
|
|
is = p.getInputStream();
|
|
|
|
reader = new BufferedReader(new InputStreamReader(is));
|
|
while ((line = reader.readLine()) != null)
|
|
{
|
|
readelfLoadMatcher.reset(line);
|
|
if (readelfLoadMatcher.matches())
|
|
{
|
|
loadAddr
|
|
= Long.decode(readelfLoadMatcher.group(2)).longValue();
|
|
break;
|
|
}
|
|
}
|
|
es.close();
|
|
is.close();
|
|
p.destroy();
|
|
}
|
|
|
|
System.out.println(ToolPrefix.toolPrefix + "nm " + filename
|
|
+ " -> " + count + " symbols");
|
|
}
|
|
|
|
public static void main(String args[])
|
|
{
|
|
try
|
|
{
|
|
SymbolTable st = new SymbolTable(args[0]);
|
|
st.dump();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
|
|
public static String demangleVTName(String n)
|
|
{
|
|
if (n.startsWith("_ZTVN") && n.endsWith("E"))
|
|
return demangle(n.substring(5, n.length() - 1));
|
|
else
|
|
return null;
|
|
}
|
|
|
|
public void dump()
|
|
{
|
|
for (Map.Entry<Long, String> me : map.entrySet())
|
|
{
|
|
long address = me.getKey();
|
|
String symbol = me.getValue();
|
|
System.out.println(Long.toHexString(address) + " -> " + symbol);
|
|
if (symbol.startsWith("_ZN") && symbol.endsWith("6class$E"))
|
|
{
|
|
System.out.println(" Class: "
|
|
+ demangle(symbol.substring(3, symbol.length()
|
|
- 8)));
|
|
}
|
|
else if (symbol.startsWith("_ZTVN") && symbol.endsWith("E"))
|
|
{
|
|
System.out.println(" VT: "
|
|
+ demangle(symbol.substring(5, symbol.length()
|
|
- 1)));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static String demangle(String symbol)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
for (int i=0; i<symbol.length(); )
|
|
{
|
|
int l = 0;
|
|
while (i < symbol.length())
|
|
{
|
|
int d = symbol.charAt(i);
|
|
if (d < '0' || d > '9')
|
|
break;
|
|
l = 10 * l + (d - '0');
|
|
i++;
|
|
}
|
|
if (l == 0)
|
|
break;
|
|
// copy
|
|
if (sb.length() > 0)
|
|
sb.append('.');
|
|
while (l > 0 && i < symbol.length())
|
|
{
|
|
sb.append(symbol.charAt(i));
|
|
l--;
|
|
i++;
|
|
}
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
public String getSymbol(long address)
|
|
{
|
|
String symbol = map.get(address);
|
|
if (symbol == null)
|
|
return null;
|
|
|
|
if (symbol.startsWith("_ZN") && symbol.endsWith("6class$E"))
|
|
symbol = demangle(symbol.substring(3, symbol.length() - 8));
|
|
return symbol;
|
|
}
|
|
|
|
// will return -1 if not found
|
|
public long getAddress(String symbol)
|
|
{
|
|
Long address = reverse.get(symbol);
|
|
if (address == null)
|
|
return -1;
|
|
return address.longValue();
|
|
}
|
|
}
|