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