1 /* 2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.tools; 26 27 import java.io.*; 28 import java.util.*; 29 import sun.jvm.hotspot.code.*; 30 import sun.jvm.hotspot.interpreter.*; 31 import sun.jvm.hotspot.debugger.*; 32 import sun.jvm.hotspot.debugger.cdbg.*; 33 import sun.jvm.hotspot.oops.*; 34 import sun.jvm.hotspot.runtime.*; 35 import sun.jvm.hotspot.utilities.PlatformInfo; 36 37 public class PStack extends Tool { 38 // in non-verbose mode, Method*s are not printed in java frames 39 public PStack(boolean v, boolean concurrentLocks) { 40 this.verbose = v; 41 this.concurrentLocks = concurrentLocks; 42 } 43 44 public PStack() { 45 this(true, true); 46 } 47 48 public void run() { 49 run(System.out); 50 } 51 52 public void run(PrintStream out) { 53 Debugger dbg = getAgent().getDebugger(); 54 run(out, dbg); 55 } 56 57 public void run(PrintStream out, Debugger dbg) { 58 if (PlatformInfo.getOS().equals("darwin")) { 59 out.println("Not available on Darwin"); 60 return; 61 } 62 63 CDebugger cdbg = dbg.getCDebugger(); 64 if (cdbg != null) { 65 ConcurrentLocksPrinter concLocksPrinter = null; 66 // compute and cache java Vframes. 67 initJFrameCache(); 68 if (concurrentLocks) { 69 concLocksPrinter = new ConcurrentLocksPrinter(); 70 } 71 // print Java level deadlocks 72 try { 73 DeadlockDetector.print(out); 74 } catch (Exception exp) { 75 out.println("can't print deadlock information: " + exp.getMessage()); 76 } 77 78 List l = cdbg.getThreadList(); 79 final boolean cdbgCanDemangle = cdbg.canDemangle(); 80 for (Iterator itr = l.iterator() ; itr.hasNext();) { 81 ThreadProxy th = (ThreadProxy) itr.next(); 82 try { 83 CFrame f = cdbg.topFrameForThread(th); 84 out.print("----------------- "); 85 out.print(th); 86 out.println(" -----------------"); 87 while (f != null) { 88 ClosestSymbol sym = f.closestSymbolToPC(); 89 Address pc = f.pc(); 90 out.print(pc + "\t"); 91 if (sym != null) { 92 String name = sym.getName(); 93 if (cdbgCanDemangle) { 94 name = cdbg.demangle(name); 95 } 96 out.print(name); 97 long diff = sym.getOffset(); 98 if (diff != 0L) { 99 out.print(" + 0x" + Long.toHexString(diff)); 100 } 101 out.println(); 102 } else { 103 // look for one or more java frames 104 String[] names = null; 105 // check interpreter frame 106 Interpreter interp = VM.getVM().getInterpreter(); 107 if (interp.contains(pc)) { 108 names = getJavaNames(th, f.localVariableBase()); 109 // print codelet name if we can't determine method 110 if (names == null || names.length == 0) { 111 out.print("<interpreter> "); 112 InterpreterCodelet ic = interp.getCodeletContaining(pc); 113 if (ic != null) { 114 String desc = ic.getDescription(); 115 if (desc != null) out.print(desc); 116 } 117 out.println(); 118 } 119 } else { 120 // look for known code blobs 121 CodeCache c = VM.getVM().getCodeCache(); 122 if (c.contains(pc)) { 123 CodeBlob cb = c.findBlobUnsafe(pc); 124 if (cb.isNMethod()) { 125 names = getJavaNames(th, f.localVariableBase()); 126 // just print compiled code, if can't determine method 127 if (names == null || names.length == 0) { 128 out.println("<Unknown compiled code>"); 129 } 130 } else if (cb.isBufferBlob()) { 131 out.println("<StubRoutines>"); 132 } else if (cb.isRuntimeStub()) { 133 out.println("<RuntimeStub>"); 134 } else if (cb.isDeoptimizationStub()) { 135 out.println("<DeoptimizationStub>"); 136 } else if (cb.isUncommonTrapStub()) { 137 out.println("<UncommonTrap>"); 138 } else if (cb.isExceptionStub()) { 139 out.println("<ExceptionStub>"); 140 } else if (cb.isSafepointStub()) { 141 out.println("<SafepointStub>"); 142 } else { 143 out.println("<Unknown code blob>"); 144 } 145 } else { 146 printUnknown(out); 147 } 148 } 149 // print java frames, if any 150 if (names != null && names.length != 0) { 151 // print java frame(s) 152 for (int i = 0; i < names.length; i++) { 153 out.println(names[i]); 154 } 155 } 156 } 157 f = f.sender(th); 158 } 159 } catch (Exception exp) { 160 exp.printStackTrace(); 161 // continue, may be we can do a better job for other threads 162 } 163 if (concurrentLocks) { 164 JavaThread jthread = (JavaThread) proxyToThread.get(th); 165 if (jthread != null) { 166 concLocksPrinter.print(jthread, out); 167 } 168 } 169 } // for threads 170 } else { 171 if (getDebugeeType() == DEBUGEE_REMOTE) { 172 out.println("remote configuration is not yet implemented"); 173 } else { 174 out.println("not yet implemented (debugger does not support CDebugger)!"); 175 } 176 } 177 } 178 179 public static void main(String[] args) throws Exception { 180 PStack t = new PStack(); 181 t.start(args); 182 t.stop(); 183 } 184 185 // -- Internals only below this point 186 private Map jframeCache; // Map<ThreadProxy, JavaVFrame[]> 187 private Map proxyToThread; // Map<ThreadProxy, JavaThread> 188 private PrintStream out; 189 private boolean verbose; 190 private boolean concurrentLocks; 191 192 private void initJFrameCache() { 193 // cache frames for subsequent reference 194 jframeCache = new HashMap(); 195 proxyToThread = new HashMap(); 196 Threads threads = VM.getVM().getThreads(); 197 for (JavaThread cur = threads.first(); cur != null; cur = cur.next()) { 198 List tmp = new ArrayList(10); 199 try { 200 for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { 201 tmp.add(vf); 202 } 203 } catch (Exception exp) { 204 // may be we may get frames for other threads, continue 205 // after printing stack trace. 206 exp.printStackTrace(); 207 } 208 JavaVFrame[] jvframes = new JavaVFrame[tmp.size()]; 209 System.arraycopy(tmp.toArray(), 0, jvframes, 0, jvframes.length); 210 jframeCache.put(cur.getThreadProxy(), jvframes); 211 proxyToThread.put(cur.getThreadProxy(), cur); 212 } 213 } 214 215 private void printUnknown(PrintStream out) { 216 out.println("\t????????"); 217 } 218 219 private String[] getJavaNames(ThreadProxy th, Address fp) { 220 if (fp == null) { 221 return null; 222 } 223 JavaVFrame[] jvframes = (JavaVFrame[]) jframeCache.get(th); 224 if (jvframes == null) return null; // not a java thread 225 List names = new ArrayList(10); 226 for (int fCount = 0; fCount < jvframes.length; fCount++) { 227 JavaVFrame vf = jvframes[fCount]; 228 Frame f = vf.getFrame(); 229 if (fp.equals(f.getFP())) { 230 StringBuffer sb = new StringBuffer(); 231 Method method = vf.getMethod(); 232 // a special char to identify java frames in output 233 sb.append("* "); 234 sb.append(method.externalNameAndSignature()); 235 sb.append(" bci:" + vf.getBCI()); 236 int lineNumber = method.getLineNumberFromBCI(vf.getBCI()); 237 if (lineNumber != -1) { 238 sb.append(" line:" + lineNumber); 239 } 240 241 if (verbose) { 242 sb.append(" Method*:" + method.getAddress()); 243 } 244 245 if (vf.isCompiledFrame()) { 246 sb.append(" (Compiled frame"); 247 if (vf.isDeoptimized()) { 248 sb.append(" [deoptimized]"); 249 } 250 } else if (vf.isInterpretedFrame()) { 251 sb.append(" (Interpreted frame"); 252 } 253 if (vf.mayBeImpreciseDbg()) { 254 sb.append("; information may be imprecise"); 255 } 256 sb.append(")"); 257 names.add(sb.toString()); 258 } 259 } 260 String[] res = new String[names.size()]; 261 System.arraycopy(names.toArray(), 0, res, 0, res.length); 262 return res; 263 } 264 }