blob: 9bab664f2740dafe35effa19ef78a5d359a9fc5d [file] [log] [blame]
/*
* Copyright 2003-2006 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.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.*;
public class PStack extends Tool {
// in non-verbose mode, methodOops are not printed in java frames
public PStack(boolean v, boolean concurrentLocks) {
this.verbose = v;
this.concurrentLocks = concurrentLocks;
}
public PStack() {
this(true, true);
}
public void run() {
run(System.out);
}
public void run(PrintStream out) {
Debugger dbg = getAgent().getDebugger();
run(out, dbg, getAgent().isJavaMode());
}
public void run(PrintStream out, Debugger dbg) {
run(out, dbg, true);
}
private void run(PrintStream out, Debugger dbg, final boolean isJava) {
CDebugger cdbg = dbg.getCDebugger();
if (cdbg != null) {
ConcurrentLocksPrinter concLocksPrinter = null;
if (isJava) {
// 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();
if (sym != null) {
String name = sym.getName();
if (cdbgCanDemangle) {
name = cdbg.demangle(name);
}
out.print(pc + "\t" + name);
long diff = sym.getOffset();
if (diff != 0L) {
out.print(" + 0x" + Long.toHexString(diff));
}
out.println();
} else {
if (isJava) {
// 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)) {
out.print(pc + "\t");
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,pc);
}
}
// 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(pc + "\t" + names[i]);
}
}
} else {
printUnknown(out,pc);
}
}
f = f.sender();
}
} catch (Exception exp) {
exp.printStackTrace();
// continue, may be we can do a better job for other threads
}
if (isJava && 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)!");
}
}
}
protected boolean requiresVM() {
return false;
}
public static void main(String[] args) throws Exception {
PStack t = new PStack();
t.start(args);
t.stop();
}
// -- 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, Address pc) {
out.println(pc + "\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(" methodOop:" + method.getHandle());
}
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;
}
}