1 /* 2 * Copyright (c) 2003, 2017, 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 PStack(JVMDebugger d) { 49 super(d); 50 } 51 52 public void run() { 53 run(System.out); 54 } 55 56 public void run(PrintStream out) { 57 Debugger dbg = getAgent().getDebugger(); 58 run(out, dbg); 59 } 60 61 public void run(PrintStream out, Debugger dbg) { 62 if (PlatformInfo.getOS().equals("darwin")) { 63 out.println("Not available on Darwin"); 64 return; 65 } 66 67 CDebugger cdbg = dbg.getCDebugger(); 68 if (cdbg != null) { 69 ConcurrentLocksPrinter concLocksPrinter = null; 70 // compute and cache java Vframes. 71 initJFrameCache(); 72 if (concurrentLocks) { 73 concLocksPrinter = new ConcurrentLocksPrinter(); 74 } 75 // print Java level deadlocks 76 try { 77 DeadlockDetector.print(out); 78 } catch (Exception exp) { 79 out.println("can't print deadlock information: " + exp.getMessage()); 80 } 81 82 List l = cdbg.getThreadList(); 83 final boolean cdbgCanDemangle = cdbg.canDemangle(); 84 for (Iterator itr = l.iterator() ; itr.hasNext();) { 85 ThreadProxy th = (ThreadProxy) itr.next(); 86 try { 87 CFrame f = cdbg.topFrameForThread(th); 88 out.print("----------------- "); 89 out.print(th); 90 out.println(" -----------------"); 91 JavaThread jthread = (JavaThread) proxyToThread.get(th); 92 if (jthread != null) { 93 jthread.printThreadInfoOn(out); 94 } 95 while (f != null) { 96 ClosestSymbol sym = f.closestSymbolToPC(); 97 Address pc = f.pc(); 98 out.print(pc + "\t"); 99 if (sym != null) { 100 String name = sym.getName(); 101 if (cdbgCanDemangle) { 102 name = cdbg.demangle(name); 103 } 104 out.print(name); 105 long diff = sym.getOffset(); 106 if (diff != 0L) { 107 out.print(" + 0x" + Long.toHexString(diff)); 108 } 109 out.println(); 110 } else { 111 // look for one or more java frames 112 String[] names = null; 113 // check interpreter frame 114 Interpreter interp = VM.getVM().getInterpreter(); 115 if (interp.contains(pc)) { 116 names = getJavaNames(th, f.localVariableBase()); 117 // print codelet name if we can't determine method 118 if (names == null || names.length == 0) { 119 out.print("<interpreter> "); 120 InterpreterCodelet ic = interp.getCodeletContaining(pc); 121 if (ic != null) { 122 String desc = ic.getDescription(); 123 if (desc != null) out.print(desc); 124 } 125 out.println(); 126 } 127 } else { 128 // look for known code blobs 129 CodeCache c = VM.getVM().getCodeCache(); 130 if (c.contains(pc)) { 131 CodeBlob cb = c.findBlobUnsafe(pc); 132 if (cb.isNMethod()) { 133 names = getJavaNames(th, f.localVariableBase()); 134 // just print compiled code, if can't determine method 135 if (names == null || names.length == 0) { 136 out.println("<Unknown compiled code>"); 137 } 138 } else if (cb.isBufferBlob()) { 139 out.println("<StubRoutines>"); 140 } else if (cb.isRuntimeStub()) { 141 out.println("<RuntimeStub>"); 142 } else if (cb.isDeoptimizationStub()) { 143 out.println("<DeoptimizationStub>"); 144 } else if (cb.isUncommonTrapStub()) { 145 out.println("<UncommonTrap>"); 146 } else if (cb.isExceptionStub()) { 147 out.println("<ExceptionStub>"); 148 } else if (cb.isSafepointStub()) { 149 out.println("<SafepointStub>"); 150 } else { 151 out.println("<Unknown code blob>"); 152 } 153 } else { 154 printUnknown(out); 155 } 156 } 157 // print java frames, if any 158 if (names != null && names.length != 0) { 159 // print java frame(s) 160 for (int i = 0; i < names.length; i++) { 161 out.println(names[i]); 162 } 163 } 164 } 165 f = f.sender(th); 166 } 167 } catch (Exception exp) { 168 exp.printStackTrace(); 169 // continue, may be we can do a better job for other threads 170 } 171 if (concurrentLocks) { 172 JavaThread jthread = (JavaThread) proxyToThread.get(th); 173 if (jthread != null) { 174 concLocksPrinter.print(jthread, out); 175 } 176 } 177 } // for threads 178 } else { 179 if (getDebugeeType() == DEBUGEE_REMOTE) { 180 out.println("remote configuration is not yet implemented"); 181 } else { 182 out.println("not yet implemented (debugger does not support CDebugger)!"); 183 } 184 } 185 } 186 187 public static void main(String[] args) throws Exception { 188 PStack t = new PStack(); 189 t.execute(args); 190 } 191 192 // -- Internals only below this point 193 private Map jframeCache; // Map<ThreadProxy, JavaVFrame[]> 194 private Map proxyToThread; // Map<ThreadProxy, JavaThread> 195 private PrintStream out; 196 private boolean verbose; 197 private boolean concurrentLocks; 198 199 private void initJFrameCache() { 200 // cache frames for subsequent reference 201 jframeCache = new HashMap(); 202 proxyToThread = new HashMap(); 203 VM.getVM().getThreads().doJavaThreads((cur) -> { 204 List tmp = new ArrayList(10); 205 try { 206 for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { 207 tmp.add(vf); 208 } 209 } catch (Exception exp) { 210 // may be we may get frames for other threads, continue 211 // after printing stack trace. 212 exp.printStackTrace(); 213 } 214 JavaVFrame[] jvframes = new JavaVFrame[tmp.size()]; 215 System.arraycopy(tmp.toArray(), 0, jvframes, 0, jvframes.length); 216 jframeCache.put(cur.getThreadProxy(), jvframes); 217 proxyToThread.put(cur.getThreadProxy(), cur); 218 }); 219 } 220 221 private void printUnknown(PrintStream out) { 222 out.println("\t????????"); 223 } 224 225 private String[] getJavaNames(ThreadProxy th, Address fp) { 226 if (fp == null) { 227 return null; 228 } 229 JavaVFrame[] jvframes = (JavaVFrame[]) jframeCache.get(th); 230 if (jvframes == null) return null; // not a java thread 231 List names = new ArrayList(10); 232 for (int fCount = 0; fCount < jvframes.length; fCount++) { 233 JavaVFrame vf = jvframes[fCount]; 234 Frame f = vf.getFrame(); 235 if (fp.equals(f.getFP())) { 236 StringBuffer sb = new StringBuffer(); 237 Method method = vf.getMethod(); 238 // a special char to identify java frames in output 239 sb.append("* "); 240 sb.append(method.externalNameAndSignature()); 241 sb.append(" bci:" + vf.getBCI()); 242 int lineNumber = method.getLineNumberFromBCI(vf.getBCI()); 243 if (lineNumber != -1) { 244 sb.append(" line:" + lineNumber); 245 } 246 247 if (verbose) { 248 sb.append(" Method*:" + method.getAddress()); 249 } 250 251 if (vf.isCompiledFrame()) { 252 sb.append(" (Compiled frame"); 253 if (vf.isDeoptimized()) { 254 sb.append(" [deoptimized]"); 255 } 256 } else if (vf.isInterpretedFrame()) { 257 sb.append(" (Interpreted frame"); 258 } 259 if (vf.mayBeImpreciseDbg()) { 260 sb.append("; information may be imprecise"); 261 } 262 sb.append(")"); 263 names.add(sb.toString()); 264 } 265 } 266 String[] res = new String[names.size()]; 267 System.arraycopy(names.toArray(), 0, res, 0, res.length); 268 return res; 269 } 270 }