/* * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ package sun.jvm.hotspot.tools; import java.io.*; import java.util.*; import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.interpreter.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.utilities.PlatformInfo; public class PStack extends Tool { // in non-verbose mode, Method*s are not printed in java frames public PStack(boolean v, boolean concurrentLocks) { this.verbose = v; this.concurrentLocks = concurrentLocks; } public PStack() { this(true, true); } public PStack(JVMDebugger d) { super(d); } public void run() { run(System.out); } public void run(PrintStream out) { Debugger dbg = getAgent().getDebugger(); run(out, dbg); } public void run(PrintStream out, Debugger dbg) { if (PlatformInfo.getOS().equals("darwin")) { out.println("Not available on Darwin"); return; } CDebugger cdbg = dbg.getCDebugger(); if (cdbg != null) { ConcurrentLocksPrinter concLocksPrinter = null; // compute and cache java Vframes. initJFrameCache(); if (concurrentLocks) { concLocksPrinter = new ConcurrentLocksPrinter(); } // print Java level deadlocks try { DeadlockDetector.print(out); } catch (Exception exp) { out.println("can't print deadlock information: " + exp.getMessage()); } List l = cdbg.getThreadList(); final boolean cdbgCanDemangle = cdbg.canDemangle(); for (Iterator itr = l.iterator() ; itr.hasNext();) { ThreadProxy th = (ThreadProxy) itr.next(); try { CFrame f = cdbg.topFrameForThread(th); out.print("----------------- "); out.print(th); out.println(" -----------------"); while (f != null) { ClosestSymbol sym = f.closestSymbolToPC(); Address pc = f.pc(); out.print(pc + "\t"); if (sym != null) { String name = sym.getName(); if (cdbgCanDemangle) { name = cdbg.demangle(name); } out.print(name); long diff = sym.getOffset(); if (diff != 0L) { out.print(" + 0x" + Long.toHexString(diff)); } out.println(); } else { // look for one or more java frames String[] names = null; // check interpreter frame Interpreter interp = VM.getVM().getInterpreter(); if (interp.contains(pc)) { names = getJavaNames(th, f.localVariableBase()); // print codelet name if we can't determine method if (names == null || names.length == 0) { out.print("<interpreter> "); InterpreterCodelet ic = interp.getCodeletContaining(pc); if (ic != null) { String desc = ic.getDescription(); if (desc != null) out.print(desc); } out.println(); } } else { // look for known code blobs CodeCache c = VM.getVM().getCodeCache(); if (c.contains(pc)) { CodeBlob cb = c.findBlobUnsafe(pc); if (cb.isNMethod()) { names = getJavaNames(th, f.localVariableBase()); // just print compiled code, if can't determine method if (names == null || names.length == 0) { out.println("<Unknown compiled code>"); } } else if (cb.isBufferBlob()) { out.println("<StubRoutines>"); } else if (cb.isRuntimeStub()) { out.println("<RuntimeStub>"); } else if (cb.isDeoptimizationStub()) { out.println("<DeoptimizationStub>"); } else if (cb.isUncommonTrapStub()) { out.println("<UncommonTrap>"); } else if (cb.isExceptionStub()) { out.println("<ExceptionStub>"); } else if (cb.isSafepointStub()) { out.println("<SafepointStub>"); } else { out.println("<Unknown code blob>"); } } else { printUnknown(out); } } // print java frames, if any if (names != null && names.length != 0) { // print java frame(s) for (int i = 0; i < names.length; i++) { out.println(names[i]); } } } f = f.sender(th); } } catch (Exception exp) { exp.printStackTrace(); // continue, may be we can do a better job for other threads } if (concurrentLocks) { JavaThread jthread = (JavaThread) proxyToThread.get(th); if (jthread != null) { concLocksPrinter.print(jthread, out); } } } // for threads } else { if (getDebugeeType() == DEBUGEE_REMOTE) { out.println("remote configuration is not yet implemented"); } else { out.println("not yet implemented (debugger does not support CDebugger)!"); } } } public static void main(String[] args) throws Exception { PStack t = new PStack(); t.execute(args); } // -- Internals only below this point private Map jframeCache; // Map<ThreadProxy, JavaVFrame[]> private Map proxyToThread; // Map<ThreadProxy, JavaThread> private PrintStream out; private boolean verbose; private boolean concurrentLocks; private void initJFrameCache() { // cache frames for subsequent reference jframeCache = new HashMap(); proxyToThread = new HashMap(); Threads threads = VM.getVM().getThreads(); for (JavaThread cur = threads.first(); cur != null; cur = cur.next()) { List tmp = new ArrayList(10); try { for (JavaVFrame vf = cur.getLastJavaVFrameDbg(); vf != null; vf = vf.javaSender()) { tmp.add(vf); } } catch (Exception exp) { // may be we may get frames for other threads, continue // after printing stack trace. exp.printStackTrace(); } JavaVFrame[] jvframes = new JavaVFrame[tmp.size()]; System.arraycopy(tmp.toArray(), 0, jvframes, 0, jvframes.length); jframeCache.put(cur.getThreadProxy(), jvframes); proxyToThread.put(cur.getThreadProxy(), cur); } } private void printUnknown(PrintStream out) { out.println("\t????????"); } private String[] getJavaNames(ThreadProxy th, Address fp) { if (fp == null) { return null; } JavaVFrame[] jvframes = (JavaVFrame[]) jframeCache.get(th); if (jvframes == null) return null; // not a java thread List names = new ArrayList(10); for (int fCount = 0; fCount < jvframes.length; fCount++) { JavaVFrame vf = jvframes[fCount]; Frame f = vf.getFrame(); if (fp.equals(f.getFP())) { StringBuffer sb = new StringBuffer(); Method method = vf.getMethod(); // a special char to identify java frames in output sb.append("* "); sb.append(method.externalNameAndSignature()); sb.append(" bci:" + vf.getBCI()); int lineNumber = method.getLineNumberFromBCI(vf.getBCI()); if (lineNumber != -1) { sb.append(" line:" + lineNumber); } if (verbose) { sb.append(" Method*:" + method.getAddress()); } if (vf.isCompiledFrame()) { sb.append(" (Compiled frame"); if (vf.isDeoptimized()) { sb.append(" [deoptimized]"); } } else if (vf.isInterpretedFrame()) { sb.append(" (Interpreted frame"); } if (vf.mayBeImpreciseDbg()) { sb.append("; information may be imprecise"); } sb.append(")"); names.add(sb.toString()); } } String[] res = new String[names.size()]; System.arraycopy(names.toArray(), 0, res, 0, res.length); return res; } }