|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.tools.jstack; |
|
|
|
import java.lang.reflect.Method; |
|
import java.lang.reflect.Constructor; |
|
import java.io.IOException; |
|
import java.io.InputStream; |
|
|
|
import com.sun.tools.attach.VirtualMachine; |
|
import com.sun.tools.attach.AttachNotSupportedException; |
|
import sun.tools.attach.HotSpotVirtualMachine; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class JStack { |
|
public static void main(String[] args) throws Exception { |
|
if (args.length == 0) { |
|
usage(1); |
|
} |
|
|
|
boolean useSA = false; |
|
boolean mixed = false; |
|
boolean locks = false; |
|
|
|
|
|
int optionCount = 0; |
|
while (optionCount < args.length) { |
|
String arg = args[optionCount]; |
|
if (!arg.startsWith("-")) { |
|
break; |
|
} |
|
if (arg.equals("-help") || arg.equals("-h")) { |
|
usage(0); |
|
} |
|
else if (arg.equals("-F")) { |
|
useSA = true; |
|
} |
|
else { |
|
if (arg.equals("-m")) { |
|
mixed = true; |
|
} else { |
|
if (arg.equals("-l")) { |
|
locks = true; |
|
} else { |
|
usage(1); |
|
} |
|
} |
|
} |
|
optionCount++; |
|
} |
|
|
|
|
|
if (mixed) { |
|
useSA = true; |
|
} |
|
|
|
// Next we check the parameter count. If there are two parameters |
|
|
|
int paramCount = args.length - optionCount; |
|
if (paramCount == 0 || paramCount > 2) { |
|
usage(1); |
|
} |
|
if (paramCount == 2) { |
|
useSA = true; |
|
} else { |
|
|
|
if (!args[optionCount].matches("[0-9]+")) { |
|
useSA = true; |
|
} |
|
} |
|
|
|
|
|
if (useSA) { |
|
|
|
String params[] = new String[paramCount]; |
|
for (int i=optionCount; i<args.length; i++ ){ |
|
params[i-optionCount] = args[i]; |
|
} |
|
runJStackTool(mixed, locks, params); |
|
} else { |
|
|
|
String pid = args[optionCount]; |
|
String params[]; |
|
if (locks) { |
|
params = new String[] { "-l" }; |
|
} else { |
|
params = new String[0]; |
|
} |
|
runThreadDump(pid, params); |
|
} |
|
} |
|
|
|
|
|
|
|
private static void runJStackTool(boolean mixed, boolean locks, String args[]) throws Exception { |
|
Class<?> cl = loadSAClass(); |
|
if (cl == null) { |
|
usage(1); |
|
} |
|
|
|
|
|
if (mixed) { |
|
args = prepend("-m", args); |
|
} |
|
if (locks) { |
|
args = prepend("-l", args); |
|
} |
|
|
|
Class[] argTypes = { String[].class }; |
|
Method m = cl.getDeclaredMethod("main", argTypes); |
|
|
|
Object[] invokeArgs = { args }; |
|
m.invoke(null, invokeArgs); |
|
} |
|
|
|
|
|
private static Class<?> loadSAClass() { |
|
// |
|
// Attempt to load JStack class - we specify the system class |
|
// loader so as to cater for development environments where |
|
// this class is on the boot class path but sa-jdi.jar is on |
|
// the system class path. Once the JDK is deployed then both |
|
// tools.jar and sa-jdi.jar are on the system class path. |
|
|
|
try { |
|
return Class.forName("sun.jvm.hotspot.tools.JStack", true, |
|
ClassLoader.getSystemClassLoader()); |
|
} catch (Exception x) { } |
|
return null; |
|
} |
|
|
|
|
|
private static void runThreadDump(String pid, String args[]) throws Exception { |
|
VirtualMachine vm = null; |
|
try { |
|
vm = VirtualMachine.attach(pid); |
|
} catch (Exception x) { |
|
String msg = x.getMessage(); |
|
if (msg != null) { |
|
System.err.println(pid + ": " + msg); |
|
} else { |
|
x.printStackTrace(); |
|
} |
|
if ((x instanceof AttachNotSupportedException) && |
|
(loadSAClass() != null)) { |
|
System.err.println("The -F option can be used when the target " + |
|
"process is not responding"); |
|
} |
|
System.exit(1); |
|
} |
|
|
|
// Cast to HotSpotVirtualMachine as this is implementation specific |
|
|
|
InputStream in = ((HotSpotVirtualMachine)vm).remoteDataDump((Object[])args); |
|
|
|
|
|
byte b[] = new byte[256]; |
|
int n; |
|
do { |
|
n = in.read(b); |
|
if (n > 0) { |
|
String s = new String(b, 0, n, "UTF-8"); |
|
System.out.print(s); |
|
} |
|
} while (n > 0); |
|
in.close(); |
|
vm.detach(); |
|
} |
|
|
|
|
|
private static String[] prepend(String arg, String args[]) { |
|
String[] newargs = new String[args.length+1]; |
|
newargs[0] = arg; |
|
System.arraycopy(args, 0, newargs, 1, args.length); |
|
return newargs; |
|
} |
|
|
|
|
|
private static void usage(int exit) { |
|
System.err.println("Usage:"); |
|
System.err.println(" jstack [-l] <pid>"); |
|
System.err.println(" (to connect to running process)"); |
|
|
|
if (loadSAClass() != null) { |
|
System.err.println(" jstack -F [-m] [-l] <pid>"); |
|
System.err.println(" (to connect to a hung process)"); |
|
System.err.println(" jstack [-m] [-l] <executable> <core>"); |
|
System.err.println(" (to connect to a core file)"); |
|
System.err.println(" jstack [-m] [-l] [server_id@]<remote server IP or hostname>"); |
|
System.err.println(" (to connect to a remote debug server)"); |
|
} |
|
|
|
System.err.println(""); |
|
System.err.println("Options:"); |
|
|
|
if (loadSAClass() != null) { |
|
System.err.println(" -F to force a thread dump. Use when jstack <pid> does not respond" + |
|
" (process is hung)"); |
|
System.err.println(" -m to print both java and native frames (mixed mode)"); |
|
} |
|
|
|
System.err.println(" -l long listing. Prints additional information about locks"); |
|
System.err.println(" -h or -help to print this help message"); |
|
System.exit(exit); |
|
} |
|
} |