1 29 30 package com.caucho.java; 31 32 import com.caucho.bytecode.Attribute; 33 import com.caucho.bytecode.ByteCodeParser; 34 import com.caucho.bytecode.JavaClass; 35 import com.caucho.bytecode.OpaqueAttribute; 36 import com.caucho.loader.SimpleLoader; 37 import com.caucho.util.L10N; 38 import com.caucho.util.Log; 39 import com.caucho.vfs.ReadStream; 40 import com.caucho.vfs.Vfs; 41 42 import java.io.ByteArrayInputStream ; 43 import java.io.IOException ; 44 import java.io.InputStream ; 45 import java.io.PrintWriter ; 46 import java.util.HashMap ; 47 import java.util.WeakHashMap ; 48 import java.util.logging.Level ; 49 import java.util.logging.Logger ; 50 51 54 public class ScriptStackTrace { 55 private static final L10N L = new L10N(ScriptStackTrace.class); 56 private static final Logger log = Log.open(ScriptStackTrace.class); 57 58 private static WeakHashMap <Class ,LineMap> _scriptMap = 59 new WeakHashMap <Class ,LineMap>(); 60 61 64 public static void printStackTrace(Throwable e, PrintWriter out) 65 { 66 StackTraceElement lastHead = null; 67 68 ClassLoader loader = SimpleLoader.create(WorkDir.getLocalWorkDir()); 69 70 while (true) { 71 if (e.getMessage() != null) 72 out.println(e.getClass().getName() + ": " + e.getMessage()); 73 else 74 out.println(e.getClass().getName()); 75 76 StackTraceElement []trace = e.getStackTrace(); 77 StackTraceElement nextHead = trace.length > 0 ? trace[0] : null; 78 79 for (int i = 0; i < trace.length; i++) { 80 if (trace[i].equals(lastHead)) 81 break; 82 83 out.print("\tat "); 84 85 printStackTraceElement(trace[i], out, loader); 86 } 87 88 lastHead = nextHead; 89 90 Throwable cause = e.getCause(); 91 92 if (cause != null) { 93 out.print("Caused by: "); 94 e = cause; 95 } 96 else 97 break; 98 } 99 } 100 101 104 private static void printStackTraceElement(StackTraceElement trace, 105 PrintWriter out, 106 ClassLoader loader) 107 { 108 try { 109 LineMap map = getScriptLineMap(trace.getClassName(), loader); 110 111 if (map != null) { 112 LineMap.Line line = map.getLine(trace.getLineNumber()); 113 if (line != null) { 114 out.print(trace.getClassName() + "." + trace.getMethodName()); 115 out.print("(" + line.getSourceFilename() + ":"); 116 out.println(line.getSourceLine(trace.getLineNumber()) + ")"); 117 return; 118 } 119 } 120 } catch (Throwable e) { 121 } 122 123 out.println(trace); 124 } 125 126 129 public static LineMap getScriptLineMap(String className, ClassLoader loader) 130 { 131 try { 132 Class cl = loader.loadClass(className); 133 134 LineMap map = _scriptMap.get(cl); 135 136 if (map == null) { 137 map = loadScriptMap(cl); 138 _scriptMap.put(cl, map); 139 } 140 141 return map; 142 } catch (Throwable e) { 143 return null; 144 } 145 } 146 147 148 151 private static LineMap loadScriptMap(Class cl) 152 { 153 ClassLoader loader = cl.getClassLoader(); 154 155 if (loader == null) 156 return new LineMap(); 158 try { 159 String pathName = cl.getName().replace('.', '/') + ".class"; 160 161 InputStream is = loader.getResourceAsStream(pathName); 162 163 if (is == null) 164 return null; 165 166 try { 167 JavaClass jClass = new ByteCodeParser().parse(is); 168 169 Attribute attr = jClass.getAttribute("SourceDebugExtension"); 170 171 if (attr == null) { 172 int p = cl.getName().indexOf('$'); 173 174 if (p > 0) { 175 String className = cl.getName().substring(0, p); 176 177 return loadScriptMap(loader.loadClass(className)); 178 } 179 180 return new LineMap(); 181 } 182 else if (attr instanceof OpaqueAttribute) { 183 byte []value = ((OpaqueAttribute) attr).getValue(); 184 185 ByteArrayInputStream bis = new ByteArrayInputStream (value); 186 187 ReadStream rs = Vfs.openRead(bis); 188 rs.setEncoding("UTF-8"); 189 190 try { 191 return parseSmap(rs); 192 } finally { 193 rs.close(); 194 } 195 } 196 else 197 throw new IllegalStateException (L.l("Expected opaque attribute at '{0}'", 198 attr)); 199 } finally { 200 if (is != null) 201 is.close(); 202 } 203 } catch (Throwable e) { 204 log.log(Level.FINER, e.toString(), e); 205 206 return new LineMap(); } 208 } 209 210 213 private static LineMap parseSmap(ReadStream is) 214 throws IOException 215 { 216 String smap = is.readln(); 217 218 if (! smap.equals("SMAP")) 219 throw new IOException (L.l("Illegal header")); 220 221 222 String outputFile = is.readln().trim(); 223 String defaultStratum = is.readln().trim(); 224 225 String stratum = defaultStratum; 226 HashMap <String ,String > fileMap = new HashMap <String ,String >(); 227 228 LineMap lineMap = new LineMap(outputFile); 229 230 loop: 231 while (true) { 232 int ch = is.read(); 233 234 if (ch < 0) 235 break; 236 237 if (ch != '*') 238 throw new IOException (L.l("unexpected character '{0}'", 239 String.valueOf((char) ch))); 240 241 int code = is.read(); 242 String value = is.readln(); 243 244 switch (code) { 245 case 'E': 246 break loop; 247 248 case 'S': 249 stratum = value.trim(); 250 break; 251 252 case 'F': 253 while ((ch = is.read()) > 0 && ch != '*') { 254 if (ch == '+') { 255 String first = is.readln().trim(); 256 String second = is.readln().trim(); 257 258 int p = first.indexOf(' '); 259 String key = first.substring(0, p); 260 String file = first.substring(p + 1).trim(); 261 262 if (fileMap.size() == 0) 263 fileMap.put("", second); 264 265 fileMap.put(key, second); 266 } 267 else { 268 String first = is.readln().trim(); 269 270 int p = first.indexOf(' '); 271 String key = first.substring(0, p); 272 String file = first.substring(p + 1).trim(); 273 274 if (fileMap.size() == 0) 275 fileMap.put("", file); 276 277 fileMap.put(key, file); 278 } 279 } 280 if (ch == '*') 281 is.unread(); 282 break; 283 284 case 'L': 285 while ((ch = is.read()) != '*' && ch > 0) { 286 is.unread(); 287 288 String line = is.readln().trim(); 289 290 addMap(line, fileMap, lineMap); 291 } 292 if (ch == '*') 293 is.unread(); 294 break; 295 296 default: 297 while ((ch = is.read()) != '*') { 298 is.readln(); 299 } 300 if (ch == '*') 301 is.unread(); 302 break; 303 } 304 } 305 306 307 return lineMap; 308 } 309 310 private static void addMap(String line, 311 HashMap <String ,String > fileMap, 312 LineMap lineMap) 313 { 314 int colon = line.indexOf(':'); 315 316 if (colon < 0) 317 return; 318 319 int hash = line.indexOf('#'); 320 int startLine = 0; 321 String fileId = ""; 322 int repeatCount = 1; 323 324 if (hash < 0) 325 startLine = Integer.parseInt(line.substring(0, colon)); 326 else { 327 startLine = Integer.parseInt(line.substring(0, hash)); 328 329 int comma = line.indexOf(',', hash); 330 331 if (comma > 0 && comma < colon) { 332 fileId = line.substring(hash + 1, comma).trim(); 333 repeatCount = Integer.parseInt(line.substring(comma + 1, colon)); 334 } 335 else 336 fileId = line.substring(hash + 1, colon).trim(); 337 } 338 339 int outputLine = -1; 340 int outputIncrement = 1; 341 342 int comma = line.indexOf(',', colon); 343 344 if (comma > 0) { 345 outputLine = Integer.parseInt(line.substring(colon + 1, comma)); 346 outputIncrement = Integer.parseInt(line.substring(comma + 1)); 347 } 348 else 349 outputLine = Integer.parseInt(line.substring(colon + 1)); 350 351 String file = fileMap.get(fileId); 352 353 lineMap.addLine(startLine, file, repeatCount, outputLine, outputIncrement); 354 } 355 } 356 | Popular Tags |