1 /*
   2  * Copyright (c) 2015, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot;
  26 
  27 import java.util.ArrayList;
  28 import java.util.Arrays;
  29 
  30 import sun.jvm.hotspot.tools.JStack;
  31 import sun.jvm.hotspot.tools.JMap;
  32 import sun.jvm.hotspot.tools.JInfo;
  33 import sun.jvm.hotspot.tools.JSnap;
  34 
  35 public class SALauncher {
  36 
  37     private static boolean launcherHelp() {
  38         System.out.println("    clhsdb       \tcommand line debugger");
  39         System.out.println("    hsdb         \tui debugger");
  40         System.out.println("    jstack --help\tto get more information");
  41         System.out.println("    jmap   --help\tto get more information");
  42         System.out.println("    jinfo  --help\tto get more information");
  43         System.out.println("    jsnap  --help\tto get more information");
  44         return false;
  45     }
  46 
  47     private static boolean commonHelp() {
  48         // --pid <pid>
  49         // --exe <exe>
  50         // --core <core>
  51         System.out.println("    --exe\texecutable image name");
  52         System.out.println("    --core\tpath to coredump");
  53         System.out.println("    --pid\tpid of process to attach");
  54         return false;
  55     }
  56 
  57     private static boolean jinfoHelp() {
  58         // --flags -> -flags
  59         // --sysprops -> -sysprops
  60         System.out.println("    --flags\tto print VM flags");
  61         System.out.println("    --sysprops\tto print Java System properties");
  62         System.out.println("    <no option>\tto print both of the above");
  63         return commonHelp();
  64     }
  65 
  66     private static boolean jmapHelp() {
  67         // --heap -> -heap
  68         // --binaryheap -> -heap:format=b
  69         // --histo -> -histo
  70         // --clstats -> -clstats
  71         // --finalizerinfo -> -finalizerinfo
  72 
  73         System.out.println("    <no option>\tto print same info as Solaris pmap");
  74         System.out.println("    --heap\tto print java heap summary");
  75         System.out.println("    --binaryheap\tto dump java heap in hprof binary format");
  76         System.out.println("    --dumpfile\tname of the dump file");
  77         System.out.println("    --histo\tto print histogram of java object heap");
  78         System.out.println("    --clstats\tto print class loader statistics");
  79         System.out.println("    --finalizerinfo\tto print information on objects awaiting finalization");
  80         return commonHelp();
  81     }
  82 
  83     private static boolean jstackHelp() {
  84         // --locks -> -l
  85         // --mixed -> -m
  86         System.out.println("    --locks\tto print java.util.concurrent locks");
  87         System.out.println("    --mixed\tto print both java and native frames (mixed mode)");
  88         return commonHelp();
  89     }
  90 
  91     private static boolean jsnapHelp() {
  92         System.out.println("    --all\tto print all performance counters");
  93         return commonHelp();
  94     }
  95 
  96     private static boolean toolHelp(String toolName) {
  97         if (toolName.equals("jstack")) {
  98             return jstackHelp();
  99         }
 100         if (toolName.equals("jinfo")) {
 101             return jinfoHelp();
 102         }
 103         if (toolName.equals("jmap")) {
 104             return jmapHelp();
 105         }
 106         if (toolName.equals("jsnap")) {
 107             return jsnapHelp();
 108         }
 109         if (toolName.equals("hsdb") || toolName.equals("clhsdb")) {
 110             return commonHelp();
 111         }
 112         return launcherHelp();
 113     }
 114 
 115     private static void buildAttachArgs(ArrayList<String> newArgs, String pid,
 116                                   String exe, String core, boolean allowEmpty) {
 117         if (!allowEmpty && (pid == null) && (exe == null)) {
 118             throw new SAGetoptException("You have to set --pid or --exe.");
 119         }
 120 
 121         if (pid != null) { // Attach to live process
 122             if (exe != null) {
 123                 throw new SAGetoptException("Unnecessary argument: --exe");
 124             } else if (core != null) {
 125                 throw new SAGetoptException("Unnecessary argument: --core");
 126             } else if (!pid.matches("^\\d+$")) {
 127                 throw new SAGetoptException("Invalid pid: " + pid);
 128             }
 129 
 130             newArgs.add(pid);
 131         } else if (exe != null) {
 132             if (exe.length() == 0) {
 133                 throw new SAGetoptException("You have to set --exe.");
 134             }
 135 
 136             newArgs.add(exe);
 137 
 138             if ((core == null) || (core.length() == 0)) {
 139                 throw new SAGetoptException("You have to set --core.");
 140             }
 141 
 142             newArgs.add(core);
 143         }
 144     }
 145 
 146     private static void runCLHSDB(String[] oldArgs) {
 147         SAGetopt sg = new SAGetopt(oldArgs);
 148         String[] longOpts = {"exe=", "core=", "pid="};
 149 
 150         ArrayList<String> newArgs = new ArrayList();
 151         String pid = null;
 152         String exe = null;
 153         String core = null;
 154         String s = null;
 155 
 156         while((s = sg.next(null, longOpts)) != null) {
 157             if (s.equals("exe")) {
 158                 exe = sg.getOptarg();
 159                 continue;
 160             }
 161             if (s.equals("core")) {
 162                 core = sg.getOptarg();
 163                 continue;
 164             }
 165             if (s.equals("pid")) {
 166                 pid = sg.getOptarg();
 167                 continue;
 168             }
 169         }
 170 
 171         buildAttachArgs(newArgs, pid, exe, core, true);
 172         CLHSDB.main(newArgs.toArray(new String[newArgs.size()]));
 173     }
 174 
 175     private static void runHSDB(String[] oldArgs) {
 176         SAGetopt sg = new SAGetopt(oldArgs);
 177         String[] longOpts = {"exe=", "core=", "pid="};
 178 
 179         ArrayList<String> newArgs = new ArrayList();
 180         String pid = null;
 181         String exe = null;
 182         String core = null;
 183         String s = null;
 184 
 185         while((s = sg.next(null, longOpts)) != null) {
 186             if (s.equals("exe")) {
 187                 exe = sg.getOptarg();
 188                 continue;
 189             }
 190             if (s.equals("core")) {
 191                 core = sg.getOptarg();
 192                 continue;
 193             }
 194             if (s.equals("pid")) {
 195                 pid = sg.getOptarg();
 196                 continue;
 197             }
 198         }
 199 
 200         buildAttachArgs(newArgs, pid, exe, core, true);
 201         HSDB.main(newArgs.toArray(new String[newArgs.size()]));
 202     }
 203 
 204     private static void runJSTACK(String[] oldArgs) {
 205         SAGetopt sg = new SAGetopt(oldArgs);
 206         String[] longOpts = {"exe=", "core=", "pid=",
 207                                  "mixed", "locks"};
 208 
 209         ArrayList<String> newArgs = new ArrayList();
 210         String pid = null;
 211         String exe = null;
 212         String core = null;
 213         String s = null;
 214 
 215         while((s = sg.next(null, longOpts)) != null) {
 216             if (s.equals("exe")) {
 217                 exe = sg.getOptarg();
 218                 continue;
 219             }
 220             if (s.equals("core")) {
 221                 core = sg.getOptarg();
 222                 continue;
 223             }
 224             if (s.equals("pid")) {
 225                 pid = sg.getOptarg();
 226                 continue;
 227             }
 228             if (s.equals("mixed")) {
 229                 newArgs.add("-m");
 230                 continue;
 231             }
 232             if (s.equals("locks")) {
 233                 newArgs.add("-l");
 234                 continue;
 235             }
 236         }
 237 
 238         buildAttachArgs(newArgs, pid, exe, core, false);
 239         JStack.main(newArgs.toArray(new String[newArgs.size()]));
 240     }
 241 
 242     private static void runJMAP(String[] oldArgs) {
 243         SAGetopt sg = new SAGetopt(oldArgs);
 244         String[] longOpts = {"exe=", "core=", "pid=",
 245               "heap", "binaryheap", "dumpfile=", "histo", "clstats", "finalizerinfo"};
 246 
 247         ArrayList<String> newArgs = new ArrayList();
 248         String pid = null;
 249         String exe = null;
 250         String core = null;
 251         String s = null;
 252         String dumpfile = null;
 253         boolean requestHeapdump = false;
 254 
 255         while((s = sg.next(null, longOpts)) != null) {
 256             if (s.equals("exe")) {
 257                 exe = sg.getOptarg();
 258                 continue;
 259             }
 260             if (s.equals("core")) {
 261                 core = sg.getOptarg();
 262                 continue;
 263             }
 264             if (s.equals("pid")) {
 265                 pid = sg.getOptarg();
 266                 continue;
 267             }
 268             if (s.equals("heap")) {
 269                 newArgs.add("-heap");
 270                 continue;
 271             }
 272             if (s.equals("binaryheap")) {
 273                 requestHeapdump = true;
 274                 continue;
 275             }
 276             if (s.equals("dumpfile")) {
 277                 dumpfile = sg.getOptarg();
 278                 continue;
 279             }
 280             if (s.equals("histo")) {
 281                 newArgs.add("-histo");
 282                 continue;
 283             }
 284             if (s.equals("clstats")) {
 285                 newArgs.add("-clstats");
 286                 continue;
 287             }
 288             if (s.equals("finalizerinfo")) {
 289                 newArgs.add("-finalizerinfo");
 290                 continue;
 291             }
 292         }
 293 
 294         if (requestHeapdump) {
 295             if (dumpfile == null) {
 296                 newArgs.add("-heap:format=b");
 297             } else {
 298                 newArgs.add("-heap:format=b,file=" + dumpfile);
 299             }
 300         } else if (dumpfile != null) {
 301             throw new IllegalArgumentException("dumpfile does not need.");
 302         }
 303 
 304         buildAttachArgs(newArgs, pid, exe, core, false);
 305         JMap.main(newArgs.toArray(new String[newArgs.size()]));
 306     }
 307 
 308     private static void runJINFO(String[] oldArgs) {
 309         SAGetopt sg = new SAGetopt(oldArgs);
 310         String[] longOpts = {"exe=", "core=", "pid=",
 311                                      "flags", "sysprops"};
 312 
 313         ArrayList<String> newArgs = new ArrayList();
 314         String exe = null;
 315         String pid = null;
 316         String core = null;
 317         String s = null;
 318 
 319         while((s = sg.next(null, longOpts)) != null) {
 320             if (s.equals("exe")) {
 321                 exe = sg.getOptarg();
 322                 continue;
 323             }
 324             if (s.equals("core")) {
 325                 core = sg.getOptarg();
 326                 continue;
 327             }
 328             if (s.equals("pid")) {
 329                 pid = sg.getOptarg();
 330                 continue;
 331             }
 332             if (s.equals("flags")) {
 333                 newArgs.add("-flags");
 334                 continue;
 335             }
 336             if (s.equals("sysprops")) {
 337                 newArgs.add("-sysprops");
 338                 continue;
 339             }
 340         }
 341 
 342         buildAttachArgs(newArgs, pid, exe, core, false);
 343         JInfo.main(newArgs.toArray(new String[newArgs.size()]));
 344     }
 345 
 346     private static void runJSNAP(String[] oldArgs) {
 347         SAGetopt sg = new SAGetopt(oldArgs);
 348         String[] longOpts = {"exe=", "core=", "pid=", "all"};
 349 
 350         ArrayList<String> newArgs = new ArrayList();
 351         String exe = null;
 352         String pid = null;
 353         String core = null;
 354         String s = null;
 355 
 356         while((s = sg.next(null, longOpts)) != null) {
 357             if (s.equals("exe")) {
 358                 exe = sg.getOptarg();
 359                 continue;
 360             }
 361             if (s.equals("core")) {
 362                 core = sg.getOptarg();
 363                 continue;
 364             }
 365             if (s.equals("pid")) {
 366                 pid = sg.getOptarg();
 367                 continue;
 368             }
 369             if (s.equals("all")) {
 370                 newArgs.add("-a");
 371                 continue;
 372             }
 373         }
 374 
 375         buildAttachArgs(newArgs, pid, exe, core, false);
 376         JSnap.main(newArgs.toArray(new String[newArgs.size()]));
 377     }
 378 
 379     public static void main(String[] args) {
 380         // Provide a help
 381         if (args.length == 0) {
 382             launcherHelp();
 383             return;
 384         }
 385         // No arguments imply help for jstack, jmap, jinfo but launch clhsdb and hsdb
 386         if (args.length == 1 && !args[0].equals("clhsdb") && !args[0].equals("hsdb")) {
 387             toolHelp(args[0]);
 388             return;
 389         }
 390 
 391         for (String arg : args) {
 392             if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help")) {
 393                 toolHelp(args[0]);
 394                 return;
 395             }
 396         }
 397 
 398         String[] oldArgs = Arrays.copyOfRange(args, 1, args.length);
 399 
 400         try {
 401             // Run SA interactive mode
 402             if (args[0].equals("clhsdb")) {
 403                 runCLHSDB(oldArgs);
 404                 return;
 405             }
 406 
 407             if (args[0].equals("hsdb")) {
 408                 runHSDB(oldArgs);
 409                 return;
 410             }
 411 
 412             // Run SA tmtools mode
 413             if (args[0].equals("jstack")) {
 414                 runJSTACK(oldArgs);
 415                 return;
 416             }
 417 
 418             if (args[0].equals("jmap")) {
 419                 runJMAP(oldArgs);
 420                 return;
 421             }
 422 
 423             if (args[0].equals("jinfo")) {
 424                 runJINFO(oldArgs);
 425                 return;
 426             }
 427 
 428             if (args[0].equals("jsnap")) {
 429                 runJSNAP(oldArgs);
 430                 return;
 431             }
 432 
 433             throw new SAGetoptException("Unknown tool: " + args[0]);
 434         } catch (SAGetoptException e) {
 435             System.err.println(e.getMessage());
 436             toolHelp(args[0]);
 437         }
 438     }
 439 }