1 /* SymbolTable.java -- Maintains a mapping of addresses to names.
2    Copyright (C) 2007  Free Software Foundation
3 
4    This file is part of libgcj.
5 
6    This software is copyrighted work licensed under the terms of the
7    Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
8    details.  */
9 
10 package gnu.gcj.tools.gc_analyze;
11 
12 import java.io.BufferedReader;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.InputStreamReader;
16 import java.util.HashMap;
17 import java.util.Map;
18 import java.util.regex.Matcher;
19 import java.util.regex.Pattern;
20 
21 class SymbolTable
22 {
23   // Long address->String name
24   private HashMap<Long, String> map = new HashMap<Long, String>();
25 
26   // Reverse
27   // String name -> Long address
28   // used for RelocateImage
29   private HashMap<String, Long> reverse = new HashMap<String, Long>();
30 
31   long loadAddr;
32   long relocation;
33 
34   static Matcher interestingSymbol =
35     Pattern.compile("^([0-9a-fA-F]+)\\s+\\S+\\s+(_Z\\S+)").matcher("");
36   static Matcher readelfLoadMatcher =
37     Pattern.compile("^\\s+LOAD\\s+(\\S+)\\s+(\\S+)\\s.*").matcher("");
38 
SymbolTable(String filename)39   public SymbolTable(String filename) throws IOException
40   {
41     Process p = Runtime.getRuntime().exec(ToolPrefix.toolPrefix
42                                           + "nm " + filename);
43     InputStream es = p.getErrorStream();
44     InputStream is = p.getInputStream();
45 
46     BufferedReader reader = new BufferedReader(new InputStreamReader(is));
47     int count = 0;
48 
49     String line;
50     while ((line = reader.readLine()) != null)
51       {
52         interestingSymbol.reset(line);
53         if (interestingSymbol.matches())
54           {
55             try
56               {
57                 String name = interestingSymbol.group(2);
58                 String addr = interestingSymbol.group(1);
59                 if (name.startsWith("_ZTVN") || name.endsWith("6class$E"))
60                   {
61                     long address = MemoryMap.parseHexLong(addr);
62                     Long l = new Long(address);
63                     map.put(l, name);
64                     count++;
65                     reverse.put(name, l);
66                   }
67               }
68             catch (NumberFormatException e)
69               {
70                 // ignore it
71               }
72           }
73       }
74     es.close();
75     is.close();
76     p.destroy();
77 
78     if (count > 0)
79       {
80         // Assume nm read some symbols from it and that
81         // readelf can tell us something about how it is loaded.
82         p = Runtime.getRuntime().exec(ToolPrefix.toolPrefix
83                                       + "readelf -l " + filename);
84         es = p.getErrorStream();
85         is = p.getInputStream();
86 
87         reader = new BufferedReader(new InputStreamReader(is));
88         while ((line = reader.readLine()) != null)
89           {
90             readelfLoadMatcher.reset(line);
91             if (readelfLoadMatcher.matches())
92               {
93                 loadAddr
94                   = Long.decode(readelfLoadMatcher.group(2)).longValue();
95                 break;
96               }
97           }
98         es.close();
99         is.close();
100         p.destroy();
101       }
102 
103     System.out.println(ToolPrefix.toolPrefix + "nm " + filename
104                        + " -> " + count + " symbols");
105   }
106 
main(String args[])107   public static void main(String args[])
108   {
109     try
110       {
111         SymbolTable st = new SymbolTable(args[0]);
112         st.dump();
113       }
114     catch (Exception ex)
115       {
116         ex.printStackTrace();
117       }
118   }
119 
demangleVTName(String n)120   public static String demangleVTName(String n)
121   {
122     if (n.startsWith("_ZTVN") && n.endsWith("E"))
123       return demangle(n.substring(5, n.length() - 1));
124     else
125       return null;
126   }
127 
dump()128   public void dump()
129   {
130     for (Map.Entry<Long, String> me : map.entrySet())
131       {
132         long address = me.getKey();
133         String symbol = me.getValue();
134         System.out.println(Long.toHexString(address) + " -> " + symbol);
135         if (symbol.startsWith("_ZN") && symbol.endsWith("6class$E"))
136           {
137             System.out.println("  Class: "
138                                + demangle(symbol.substring(3, symbol.length()
139                                                            - 8)));
140           }
141         else if (symbol.startsWith("_ZTVN") && symbol.endsWith("E"))
142           {
143             System.out.println("  VT: "
144                                + demangle(symbol.substring(5, symbol.length()
145                                                            - 1)));
146           }
147       }
148   }
149 
demangle(String symbol)150   private static String demangle(String symbol)
151   {
152     StringBuilder sb = new StringBuilder();
153     for (int i=0; i<symbol.length(); )
154       {
155         int l = 0;
156         while (i < symbol.length())
157           {
158             int d = symbol.charAt(i);
159             if (d < '0' || d > '9')
160               break;
161             l = 10 * l + (d - '0');
162             i++;
163           }
164         if (l == 0)
165           break;
166         // copy
167         if (sb.length() > 0)
168           sb.append('.');
169         while (l > 0 && i < symbol.length())
170           {
171             sb.append(symbol.charAt(i));
172             l--;
173             i++;
174           }
175       }
176     return sb.toString();
177   }
178 
getSymbol(long address)179   public String getSymbol(long address)
180   {
181     String symbol = map.get(address);
182     if (symbol == null)
183       return null;
184 
185     if (symbol.startsWith("_ZN") && symbol.endsWith("6class$E"))
186       symbol = demangle(symbol.substring(3, symbol.length() - 8));
187     return symbol;
188   }
189 
190   // will return -1 if not found
getAddress(String symbol)191   public long getAddress(String symbol)
192   {
193     Long address = reverse.get(symbol);
194     if (address == null)
195       return -1;
196     return address.longValue();
197   }
198 }
199