001: /*
002: * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.tools.jstack;
027:
028: import java.lang.reflect.Method;
029: import java.lang.reflect.Constructor;
030: import java.io.IOException;
031: import java.io.InputStream;
032:
033: import com.sun.tools.attach.VirtualMachine;
034: import com.sun.tools.attach.AttachNotSupportedException;
035: import sun.tools.attach.HotSpotVirtualMachine;
036:
037: /*
038: * This class is the main class for the JStack utility. It parses its arguments
039: * and decides if the command should be executed by the SA JStack tool or by
040: * obtained the thread dump from a target process using the VM attach mechanism
041: */
042: public class JStack {
043: public static void main(String[] args) throws Exception {
044: if (args.length == 0) {
045: usage(); // no arguments
046: }
047:
048: boolean useSA = false;
049: boolean mixed = false;
050: boolean locks = false;
051:
052: // Parse the options (arguments starting with "-" )
053: int optionCount = 0;
054: while (optionCount < args.length) {
055: String arg = args[optionCount];
056: if (!arg.startsWith("-")) {
057: break;
058: }
059: if (arg.equals("-F")) {
060: useSA = true;
061: } else {
062: if (arg.equals("-m")) {
063: mixed = true;
064: } else {
065: if (arg.equals("-l")) {
066: locks = true;
067: } else {
068: usage();
069: }
070: }
071: }
072: optionCount++;
073: }
074:
075: // mixed stack implies SA tool
076: if (mixed) {
077: useSA = true;
078: }
079:
080: // Next we check the parameter count. If there are two parameters
081: // we assume core file and executable so we use SA.
082: int paramCount = args.length - optionCount;
083: if (paramCount == 0 || paramCount > 2) {
084: usage();
085: }
086: if (paramCount == 2) {
087: useSA = true;
088: } else {
089: // If we can't parse it as a pid then it must be debug server
090: if (!args[optionCount].matches("[0-9]+")) {
091: useSA = true;
092: }
093: }
094:
095: // now execute using the SA JStack tool or the built-in thread dumper
096: if (useSA) {
097: // parameters (<pid> or <exe> <core>
098: String params[] = new String[paramCount];
099: for (int i = optionCount; i < args.length; i++) {
100: params[i - optionCount] = args[i];
101: }
102: runJStackTool(mixed, locks, params);
103: } else {
104: // pass -l to thread dump operation to get extra lock info
105: String pid = args[optionCount];
106: String params[];
107: if (locks) {
108: params = new String[] { "-l" };
109: } else {
110: params = new String[0];
111: }
112: runThreadDump(pid, params);
113: }
114: }
115:
116: // SA JStack tool
117: private static void runJStackTool(boolean mixed, boolean locks,
118: String args[]) throws Exception {
119: Class<?> cl = loadSAClass();
120: if (cl == null) {
121: usage(); // SA not available
122: }
123:
124: // JStack tool also takes -m and -l arguments
125: if (mixed) {
126: args = prepend("-m", args);
127: }
128: if (locks) {
129: args = prepend("-l", args);
130: }
131:
132: Class[] argTypes = { String[].class };
133: Method m = cl.getDeclaredMethod("main", argTypes);
134:
135: Object[] invokeArgs = { args };
136: m.invoke(null, invokeArgs);
137: }
138:
139: // Returns sun.jvm.hotspot.tools.JStack if available, otherwise null.
140: private static Class loadSAClass() {
141: //
142: // Attempt to load JStack class - we specify the system class
143: // loader so as to cater for development environments where
144: // this class is on the boot class path but sa-jdi.jar is on
145: // the system class path. Once the JDK is deployed then both
146: // tools.jar and sa-jdi.jar are on the system class path.
147: //
148: try {
149: return Class.forName("sun.jvm.hotspot.tools.JStack", true,
150: ClassLoader.getSystemClassLoader());
151: } catch (Exception x) {
152: }
153: return null;
154: }
155:
156: // Attach to pid and perform a thread dump
157: private static void runThreadDump(String pid, String args[])
158: throws Exception {
159: VirtualMachine vm = null;
160: try {
161: vm = VirtualMachine.attach(pid);
162: } catch (Exception x) {
163: String msg = x.getMessage();
164: if (msg != null) {
165: System.err.println(pid + ": " + msg);
166: } else {
167: x.printStackTrace();
168: }
169: if ((x instanceof AttachNotSupportedException)
170: && (loadSAClass() != null)) {
171: System.err
172: .println("The -F option can be used when the target "
173: + "process is not responding");
174: }
175: System.exit(1);
176: }
177:
178: // Cast to HotSpotVirtualMachine as this is implementation specific
179: // method.
180: InputStream in = ((HotSpotVirtualMachine) vm)
181: .remoteDataDump((Object[]) args);
182:
183: // read to EOF and just print output
184: byte b[] = new byte[256];
185: int n;
186: do {
187: n = in.read(b);
188: if (n > 0) {
189: String s = new String(b, 0, n, "UTF-8");
190: System.out.print(s);
191: }
192: } while (n > 0);
193: in.close();
194: vm.detach();
195: }
196:
197: // return a new string array with arg as the first element
198: private static String[] prepend(String arg, String args[]) {
199: String[] newargs = new String[args.length + 1];
200: newargs[0] = arg;
201: System.arraycopy(args, 0, newargs, 1, args.length);
202: return newargs;
203: }
204:
205: // print usage message
206: private static void usage() {
207: System.out.println("Usage:");
208: System.out.println(" jstack [-l] <pid>");
209: System.out.println(" (to connect to running process)");
210:
211: if (loadSAClass() != null) {
212: System.out.println(" jstack -F [-m] [-l] <pid>");
213: System.out
214: .println(" (to connect to a hung process)");
215: System.out
216: .println(" jstack [-m] [-l] <executable> <core>");
217: System.out.println(" (to connect to a core file)");
218: System.out
219: .println(" jstack [-m] [-l] [server_id@]<remote server IP or hostname>");
220: System.out
221: .println(" (to connect to a remote debug server)");
222: }
223:
224: System.out.println("");
225: System.out.println("Options:");
226:
227: if (loadSAClass() != null) {
228: System.out
229: .println(" -F to force a thread dump. Use when jstack <pid> does not respond"
230: + " (process is hung)");
231: System.out
232: .println(" -m to print both java and native frames (mixed mode)");
233: }
234:
235: System.out
236: .println(" -l long listing. Prints additional information about locks");
237: System.out
238: .println(" -h or -help to print this help message");
239: System.exit(1);
240: }
241: }
|