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("    --histo\tto print histogram of java object heap");
  77         System.out.println("    --clstats\tto print class loader statistics");
  78         System.out.println("    --finalizerinfo\tto print information on objects awaiting finalization");
  79         return commonHelp();
  80     }
  81 
  82     private static boolean jstackHelp() {
  83         // --locks -> -l
  84         // --mixed -> -m
  85         System.out.println("    --locks\tto print java.util.concurrent locks");
  86         System.out.println("    --mixed\tto print both java and native frames (mixed mode)");
  87         return commonHelp();
  88     }
  89 
  90     private static boolean jsnapHelp() {
  91         System.out.println("    --all\tto print all performance counters");
  92         return commonHelp();
  93     }
  94 
  95     private static boolean toolHelp(String toolName) {
  96         if (toolName.equals("jstack")) {
  97             return jstackHelp();
  98         }
  99         if (toolName.equals("jinfo")) {
 100             return jinfoHelp();
 101         }
 102         if (toolName.equals("jmap")) {
 103             return jmapHelp();
 104         }
 105         if (toolName.equals("jsnap")) {
 106             return jsnapHelp();
 107         }
 108         if (toolName.equals("hsdb") || toolName.equals("clhsdb")) {
 109             return commonHelp();
 110         }
 111         return launcherHelp();
 112     }
 113 
 114     private static void buildAttachArgs(ArrayList<String> newArgs, String pid,
 115                                   String exe, String core, boolean allowEmpty) {
 116         if (!allowEmpty && (pid == null) && (exe == null)) {
 117             throw new SAGetoptException("You have to set --pid or --exe.");
 118         }
 119 
 120         if (pid != null) { // Attach to live process
 121             if (exe != null) {
 122                 throw new SAGetoptException("Unnecessary argument: --exe");
 123             } else if (core != null) {
 124                 throw new SAGetoptException("Unnecessary argument: --core");
 125             } else if (!pid.matches("^\\d+$")) {
 126                 throw new SAGetoptException("Invalid pid: " + pid);
 127             }
 128 
 129             newArgs.add(pid);
 130         } else if (exe != null) {
 131             if (exe.length() == 0) {
 132                 throw new SAGetoptException("You have to set --exe.");
 133             }
 134 
 135             newArgs.add(exe);
 136 
 137             if ((core == null) || (core.length() == 0)) {
 138                 throw new SAGetoptException("You have to set --core.");
 139             }
 140 
 141             newArgs.add(core);
 142         }
 143     }
 144 
 145     private static void runCLHSDB(String[] oldArgs) {
 146         SAGetopt sg = new SAGetopt(oldArgs);
 147         String[] longOpts = {"exe=", "core=", "pid="};
 148 
 149         ArrayList<String> newArgs = new ArrayList();
 150         String pid = null;
 151         String exe = null;
 152         String core = null;
 153         String s = null;
 154 
 155         while((s = sg.next(null, longOpts)) != null) {
 156             if (s.equals("exe")) {
 157                 exe = sg.getOptarg();
 158                 continue;
 159             }
 160             if (s.equals("core")) {
 161                 core = sg.getOptarg();
 162                 continue;
 163             }
 164             if (s.equals("pid")) {
 165                 pid = sg.getOptarg();
 166                 continue;
 167             }
 168         }
 169 
 170         buildAttachArgs(newArgs, pid, exe, core, true);
 171         CLHSDB.main(newArgs.toArray(new String[newArgs.size()]));
 172     }
 173 
 174     private static void runHSDB(String[] oldArgs) {
 175         SAGetopt sg = new SAGetopt(oldArgs);
 176         String[] longOpts = {"exe=", "core=", "pid="};
 177 
 178         ArrayList<String> newArgs = new ArrayList();
 179         String pid = null;
 180         String exe = null;
 181         String core = null;
 182         String s = null;
 183 
 184         while((s = sg.next(null, longOpts)) != null) {
 185             if (s.equals("exe")) {
 186                 exe = sg.getOptarg();
 187                 continue;
 188             }
 189             if (s.equals("core")) {
 190                 core = sg.getOptarg();
 191                 continue;
 192             }
 193             if (s.equals("pid")) {
 194                 pid = sg.getOptarg();
 195                 continue;
 196             }
 197         }
 198 
 199         buildAttachArgs(newArgs, pid, exe, core, true);
 200         HSDB.main(newArgs.toArray(new String[newArgs.size()]));
 201     }
 202 
 203     private static void runJSTACK(String[] oldArgs) {
 204         SAGetopt sg = new SAGetopt(oldArgs);
 205         String[] longOpts = {"exe=", "core=", "pid=",
 206                                  "mixed", "locks"};
 207 
 208         ArrayList<String> newArgs = new ArrayList();
 209         String pid = null;
 210         String exe = null;
 211         String core = null;
 212         String s = null;
 213 
 214         while((s = sg.next(null, longOpts)) != null) {
 215             if (s.equals("exe")) {
 216                 exe = sg.getOptarg();
 217                 continue;
 218             }
 219             if (s.equals("core")) {
 220                 core = sg.getOptarg();
 221                 continue;
 222             }
 223             if (s.equals("pid")) {
 224                 pid = sg.getOptarg();
 225                 continue;
 226             }
 227             if (s.equals("mixed")) {
 228                 newArgs.add("-m");
 229                 continue;
 230             }
 231             if (s.equals("locks")) {
 232                 newArgs.add("-l");
 233                 continue;
 234             }
 235         }
 236 
 237         buildAttachArgs(newArgs, pid, exe, core, false);
 238         JStack.main(newArgs.toArray(new String[newArgs.size()]));
 239     }
 240 
 241     private static void runJMAP(String[] oldArgs) {
 242         SAGetopt sg = new SAGetopt(oldArgs);
 243         String[] longOpts = {"exe=", "core=", "pid=",
 244               "heap", "binaryheap", "histo", "clstats", "finalizerinfo"};
 245 
 246         ArrayList<String> newArgs = new ArrayList();
 247         String pid = null;
 248         String exe = null;
 249         String core = null;
 250         String s = null;
 251 
 252         while((s = sg.next(null, longOpts)) != null) {
 253             if (s.equals("exe")) {
 254                 exe = sg.getOptarg();
 255                 continue;
 256             }
 257             if (s.equals("core")) {
 258                 core = sg.getOptarg();
 259                 continue;
 260             }
 261             if (s.equals("pid")) {
 262                 pid = sg.getOptarg();
 263                 continue;
 264             }
 265             if (s.equals("heap")) {
 266                 newArgs.add("-heap");
 267                 continue;
 268             }
 269             if (s.equals("binaryheap")) {
 270                 newArgs.add("-heap:format=b");
 271                 continue;
 272             }
 273             if (s.equals("histo")) {
 274                 newArgs.add("-histo");
 275                 continue;
 276             }
 277             if (s.equals("clstats")) {
 278                 newArgs.add("-clstats");
 279                 continue;
 280             }
 281             if (s.equals("finalizerinfo")) {
 282                 newArgs.add("-finalizerinfo");
 283                 continue;
 284             }
 285         }
 286 
 287         buildAttachArgs(newArgs, pid, exe, core, false);
 288         JMap.main(newArgs.toArray(new String[newArgs.size()]));
 289     }
 290 
 291     private static void runJINFO(String[] oldArgs) {
 292         SAGetopt sg = new SAGetopt(oldArgs);
 293         String[] longOpts = {"exe=", "core=", "pid=",
 294                                      "flags", "sysprops"};
 295 
 296         ArrayList<String> newArgs = new ArrayList();
 297         String exe = null;
 298         String pid = null;
 299         String core = null;
 300         String s = null;
 301 
 302         while((s = sg.next(null, longOpts)) != null) {
 303             if (s.equals("exe")) {
 304                 exe = sg.getOptarg();
 305                 continue;
 306             }
 307             if (s.equals("core")) {
 308                 core = sg.getOptarg();
 309                 continue;
 310             }
 311             if (s.equals("pid")) {
 312                 pid = sg.getOptarg();
 313                 continue;
 314             }
 315             if (s.equals("flags")) {
 316                 newArgs.add("-flags");
 317                 continue;
 318             }
 319             if (s.equals("sysprops")) {
 320                 newArgs.add("-sysprops");
 321                 continue;
 322             }
 323         }
 324 
 325         buildAttachArgs(newArgs, pid, exe, core, false);
 326         JInfo.main(newArgs.toArray(new String[newArgs.size()]));
 327     }
 328 
 329     private static void runJSNAP(String[] oldArgs) {
 330         SAGetopt sg = new SAGetopt(oldArgs);
 331         String[] longOpts = {"exe=", "core=", "pid=", "all"};
 332 
 333         ArrayList<String> newArgs = new ArrayList();
 334         String exe = null;
 335         String pid = null;
 336         String core = null;
 337         String s = null;
 338 
 339         while((s = sg.next(null, longOpts)) != null) {
 340             if (s.equals("exe")) {
 341                 exe = sg.getOptarg();
 342                 continue;
 343             }
 344             if (s.equals("core")) {
 345                 core = sg.getOptarg();
 346                 continue;
 347             }
 348             if (s.equals("pid")) {
 349                 pid = sg.getOptarg();
 350                 continue;
 351             }
 352             if (s.equals("all")) {
 353                 newArgs.add("-a");
 354                 continue;
 355             }
 356         }
 357 
 358         buildAttachArgs(newArgs, pid, exe, core, false);
 359         JSnap.main(newArgs.toArray(new String[newArgs.size()]));
 360     }
 361 
 362     public static void main(String[] args) {
 363         // Provide a help
 364         if (args.length == 0) {
 365             launcherHelp();
 366             return;
 367         }
 368         // No arguments imply help for jstack, jmap, jinfo but launch clhsdb and hsdb
 369         if (args.length == 1 && !args[0].equals("clhsdb") && !args[0].equals("hsdb")) {
 370             toolHelp(args[0]);
 371             return;
 372         }
 373 
 374         for (String arg : args) {
 375             if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help")) {
 376                 toolHelp(args[0]);
 377                 return;
 378             }
 379         }
 380 
 381         String[] oldArgs = Arrays.copyOfRange(args, 1, args.length);
 382 
 383         try {
 384             // Run SA interactive mode
 385             if (args[0].equals("clhsdb")) {
 386                 runCLHSDB(oldArgs);
 387                 return;
 388             }
 389 
 390             if (args[0].equals("hsdb")) {
 391                 runHSDB(oldArgs);
 392                 return;
 393             }
 394 
 395             // Run SA tmtools mode
 396             if (args[0].equals("jstack")) {
 397                 runJSTACK(oldArgs);
 398                 return;
 399             }
 400 
 401             if (args[0].equals("jmap")) {
 402                 runJMAP(oldArgs);
 403                 return;
 404             }
 405 
 406             if (args[0].equals("jinfo")) {
 407                 runJINFO(oldArgs);
 408                 return;
 409             }
 410 
 411             if (args[0].equals("jsnap")) {
 412                 runJSNAP(oldArgs);
 413                 return;
 414             }
 415 
 416             throw new SAGetoptException("Unknown tool: " + args[0]);
 417         } catch (SAGetoptException e) {
 418             System.err.println(e.getMessage());
 419             toolHelp(args[0]);
 420         }
 421     }
 422 }