JInfo.java revision 10444:f08705540498
1/*
2 * Copyright (c) 2006, 2014, 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.tools.jinfo;
27
28import java.lang.reflect.Method;
29import java.util.Arrays;
30import java.io.IOException;
31import java.io.InputStream;
32
33import com.sun.tools.attach.VirtualMachine;
34
35import sun.tools.attach.HotSpotVirtualMachine;
36
37/*
38 * This class is the main class for the JInfo utility. It parses its arguments
39 * and decides if the command should be satisfied using the VM attach mechanism
40 * or an SA tool.
41 */
42final public class JInfo {
43    private boolean useSA = false;
44    private String[] args = null;
45
46    private JInfo(String[] args) throws IllegalArgumentException {
47        if (args.length == 0) {
48            throw new IllegalArgumentException();
49        }
50
51        int argCopyIndex = 0;
52        // First determine if we should launch SA or not
53        if (args[0].equals("-F")) {
54            // delete the -F
55            argCopyIndex = 1;
56            useSA = true;
57        } else if (args[0].equals("-flags")
58                   || args[0].equals("-sysprops"))
59        {
60            if (args.length == 2) {
61                if (!isPid(args[1])) {
62                    // If args[1] doesn't parse to a number then
63                    // it must be the SA debug server
64                    // (otherwise it is the pid)
65                    useSA = true;
66                }
67            } else if (args.length == 3) {
68                // arguments include an executable and a core file
69                useSA = true;
70            } else {
71                throw new IllegalArgumentException();
72            }
73        } else if (!args[0].startsWith("-")) {
74            if (args.length == 2) {
75                // the only arguments are an executable and a core file
76                useSA = true;
77            } else if (args.length == 1) {
78                if (!isPid(args[0])) {
79                    // The only argument is not a PID; it must be SA debug
80                    // server
81                    useSA = true;
82                }
83            } else {
84                throw new IllegalArgumentException();
85            }
86        } else if (args[0].equals("-h") || args[0].equals("-help")) {
87            if (args.length > 1) {
88                throw new IllegalArgumentException();
89            }
90        } else if (args[0].equals("-flag")) {
91            if (args.length == 3) {
92                if (!isPid(args[2])) {
93                    throw new IllegalArgumentException();
94                }
95            } else {
96                throw new IllegalArgumentException();
97            }
98        } else {
99            throw new IllegalArgumentException();
100        }
101
102        this.args = Arrays.copyOfRange(args, argCopyIndex, args.length);
103    }
104
105    @SuppressWarnings("fallthrough")
106    private void execute() throws Exception {
107        if (args[0].equals("-h")
108            || args[0].equals("-help")) {
109            usage(0);
110        }
111
112        if (useSA) {
113            // SA only supports -flags or -sysprops
114            if (args[0].startsWith("-")) {
115                if (!(args[0].equals("-flags") || args[0].equals("-sysprops"))) {
116                    usage(1);
117                }
118            }
119
120            // invoke SA which does it's own argument parsing
121            runTool();
122
123        } else {
124            // Now we can parse arguments for the non-SA case
125            String pid = null;
126
127            switch(args[0]) {
128                case "-flag":
129                    if (args.length != 3) {
130                        usage(1);
131                    }
132                    String option = args[1];
133                    pid = args[2];
134                    flag(pid, option);
135                    break;
136                case "-flags":
137                    if (args.length != 2) {
138                        usage(1);
139                    }
140                    pid = args[1];
141                    flags(pid);
142                    break;
143                case "-sysprops":
144                    if (args.length != 2) {
145                        usage(1);
146                    }
147                    pid = args[1];
148                    sysprops(pid);
149                    break;
150                case "-help":
151                case "-h":
152                    usage(0);
153                    // Fall through
154                default:
155                    if (args.length == 1) {
156                        // no flags specified, we do -sysprops and -flags
157                        pid = args[0];
158                        sysprops(pid);
159                        System.out.println();
160                        flags(pid);
161                        System.out.println();
162                        commandLine(pid);
163                    } else {
164                        usage(1);
165                    }
166            }
167        }
168    }
169
170    public static void main(String[] args) throws Exception {
171        JInfo jinfo = null;
172        try {
173            jinfo = new JInfo(args);
174            jinfo.execute();
175        } catch (IllegalArgumentException e) {
176            usage(1);
177        }
178    }
179
180    private static boolean isPid(String arg) {
181        return arg.matches("[0-9]+");
182    }
183
184    // Invoke SA tool with the given arguments
185    private void runTool() throws Exception {
186        String tool = "sun.jvm.hotspot.tools.JInfo";
187        // Tool not available on this platform.
188        Class<?> c = loadClass(tool);
189        if (c == null) {
190            usage(1);
191        }
192
193        // invoke the main method with the arguments
194        Class<?>[] argTypes = { String[].class } ;
195        Method m = c.getDeclaredMethod("main", argTypes);
196
197        Object[] invokeArgs = { args };
198        m.invoke(null, invokeArgs);
199    }
200
201    // loads the given class using the system class loader
202    private static Class<?> loadClass(String name) {
203        //
204        // We specify the system class loader so as to cater for development
205        // environments where this class is on the boot class path but sa-jdi.jar
206        // is on the system class path. Once the JDK is deployed then both
207        // tools.jar and sa-jdi.jar are on the system class path.
208        //
209        try {
210            return Class.forName(name, true,
211                                 ClassLoader.getSystemClassLoader());
212        } catch (Exception x)  { }
213        return null;
214    }
215
216    private static void flag(String pid, String option) throws IOException {
217        HotSpotVirtualMachine vm = (HotSpotVirtualMachine) attach(pid);
218        String flag;
219        InputStream in;
220        int index = option.indexOf('=');
221        if (index != -1) {
222            flag = option.substring(0, index);
223            String value = option.substring(index + 1);
224            in = vm.setFlag(flag, value);
225        } else {
226            char c = option.charAt(0);
227            switch (c) {
228                case '+':
229                    flag = option.substring(1);
230                    in = vm.setFlag(flag, "1");
231                    break;
232                case '-':
233                    flag = option.substring(1);
234                    in = vm.setFlag(flag, "0");
235                    break;
236                default:
237                    flag = option;
238                    in = vm.printFlag(flag);
239                    break;
240            }
241        }
242
243        drain(vm, in);
244    }
245
246    private static void flags(String pid) throws IOException {
247        HotSpotVirtualMachine vm = (HotSpotVirtualMachine) attach(pid);
248        InputStream in = vm.executeJCmd("VM.flags");
249        System.out.println("VM Flags:");
250        drain(vm, in);
251    }
252
253    private static void commandLine(String pid) throws IOException {
254        HotSpotVirtualMachine vm = (HotSpotVirtualMachine) attach(pid);
255        InputStream in = vm.executeJCmd("VM.command_line");
256        drain(vm, in);
257    }
258
259    private static void sysprops(String pid) throws IOException {
260        HotSpotVirtualMachine vm = (HotSpotVirtualMachine) attach(pid);
261        InputStream in = vm.executeJCmd("VM.system_properties");
262        System.out.println("Java System Properties:");
263        drain(vm, in);
264    }
265
266    // Attach to <pid>, exiting if we fail to attach
267    private static VirtualMachine attach(String pid) {
268        try {
269            return VirtualMachine.attach(pid);
270        } catch (Exception x) {
271            String msg = x.getMessage();
272            if (msg != null) {
273                System.err.println(pid + ": " + msg);
274            } else {
275                x.printStackTrace();
276            }
277            System.exit(1);
278            return null; // keep compiler happy
279        }
280    }
281
282    // Read the stream from the target VM until EOF, then detach
283    private static void drain(VirtualMachine vm, InputStream in) throws IOException {
284        // read to EOF and just print output
285        byte b[] = new byte[256];
286        int n;
287        do {
288            n = in.read(b);
289            if (n > 0) {
290                String s = new String(b, 0, n, "UTF-8");
291                System.out.print(s);
292            }
293        } while (n > 0);
294        in.close();
295        vm.detach();
296    }
297
298
299    // print usage message
300    private static void usage(int exit) {
301
302        Class<?> c = loadClass("sun.jvm.hotspot.tools.JInfo");
303        boolean usageSA = (c != null);
304
305        System.err.println("Usage:");
306        if (usageSA) {
307            System.err.println("    jinfo [option] <pid>");
308            System.err.println("        (to connect to a running process)");
309            System.err.println("    jinfo -F [option] <pid>");
310            System.err.println("        (to connect to a hung process)");
311            System.err.println("    jinfo [option] <executable> <core>");
312            System.err.println("        (to connect to a core file)");
313            System.err.println("    jinfo [option] [server_id@]<remote server IP or hostname>");
314            System.err.println("        (to connect to remote debug server)");
315            System.err.println("");
316            System.err.println("where <option> is one of:");
317            System.err.println("  for running processes:");
318            System.err.println("    -flag <name>         to print the value of the named VM flag");
319            System.err.println("    -flag [+|-]<name>    to enable or disable the named VM flag");
320            System.err.println("    -flag <name>=<value> to set the named VM flag to the given value");
321            System.err.println("  for running or hung processes and core files:");
322            System.err.println("    -flags               to print VM flags");
323            System.err.println("    -sysprops            to print Java system properties");
324            System.err.println("    <no option>          to print both VM flags and system properties");
325            System.err.println("    -h | -help           to print this help message");
326        } else {
327            System.err.println("    jinfo <option> <pid>");
328            System.err.println("       (to connect to a running process)");
329            System.err.println("");
330            System.err.println("where <option> is one of:");
331            System.err.println("    -flag <name>         to print the value of the named VM flag");
332            System.err.println("    -flag [+|-]<name>    to enable or disable the named VM flag");
333            System.err.println("    -flag <name>=<value> to set the named VM flag to the given value");
334            System.err.println("    -flags               to print VM flags");
335            System.err.println("    -sysprops            to print Java system properties");
336            System.err.println("    <no option>          to print both VM flags and system properties");
337            System.err.println("    -h | -help           to print this help message");
338        }
339
340        System.exit(exit);
341    }
342}
343