1 /*
   2  * Copyright (c) 2015, 2016, 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("    debugd       \tdebug server");
  40         System.out.println("    hsdb         \tui debugger");
  41         System.out.println("    jstack --help\tto get more information");
  42         System.out.println("    jmap   --help\tto get more information");
  43         System.out.println("    jinfo  --help\tto get more information");
  44         System.out.println("    jsnap  --help\tto get more information");
  45         return false;
  46     }
  47 
  48     private static boolean commonHelp() {
  49         // --pid <pid>
  50         // --exe <exe>
  51         // --core <core>
  52         System.out.println("    --exe\texecutable image name");
  53         System.out.println("    --core\tpath to coredump");
  54         System.out.println("    --pid\tpid of process to attach");
  55         return false;
  56     }
  57 
  58     private static boolean debugdHelp() {
  59         // [options] <pid> [server-id]
  60         // [options] <executable> <core> [server-id]
  61         java.io.PrintStream out = System.out;
  62         out.print(" [option] <pid> [server-id]");
  63         out.println("\t\t(to connect to a live java process)");
  64         out.print("   or  [option] <executable> <core> [server-id]");
  65         out.println("\t\t(to connect to a core file produced by <executable>)");
  66         out.print("\t\tserver-id is an optional unique id for this debug server, needed ");
  67         out.println("\t\tif multiple debug servers are run on the same machine");
  68         out.println("where option includes:");
  69         out.println("   -h | -help\tto print this help message");
  70         return false;
  71     }
  72 
  73     private static boolean jinfoHelp() {
  74         // --flags -> -flags
  75         // --sysprops -> -sysprops
  76         System.out.println("    --flags\tto print VM flags");
  77         System.out.println("    --sysprops\tto print Java System properties");
  78         System.out.println("    <no option>\tto print both of the above");
  79         return commonHelp();
  80     }
  81 
  82     private static boolean jmapHelp() {
  83         // --heap -> -heap
  84         // --binaryheap -> -heap:format=b
  85         // --histo -> -histo
  86         // --clstats -> -clstats
  87         // --finalizerinfo -> -finalizerinfo
  88 
  89         System.out.println("    <no option>\tto print same info as Solaris pmap");
  90         System.out.println("    --heap\tto print java heap summary");
  91         System.out.println("    --binaryheap\tto dump java heap in hprof binary format");
  92         System.out.println("    --dumpfile\tname of the dump file");
  93         System.out.println("    --histo\tto print histogram of java object heap");
  94         System.out.println("    --clstats\tto print class loader statistics");
  95         System.out.println("    --finalizerinfo\tto print information on objects awaiting finalization");
  96         return commonHelp();
  97     }
  98 
  99     private static boolean jstackHelp() {
 100         // --locks -> -l
 101         // --mixed -> -m
 102         System.out.println("    --locks\tto print java.util.concurrent locks");
 103         System.out.println("    --mixed\tto print both java and native frames (mixed mode)");
 104         return commonHelp();
 105     }
 106 
 107     private static boolean jsnapHelp() {
 108         System.out.println("    --all\tto print all performance counters");
 109         return commonHelp();
 110     }
 111 
 112     private static boolean toolHelp(String toolName) {
 113         if (toolName.equals("jstack")) {
 114             return jstackHelp();
 115         }
 116         if (toolName.equals("jinfo")) {
 117             return jinfoHelp();
 118         }
 119         if (toolName.equals("jmap")) {
 120             return jmapHelp();
 121         }
 122         if (toolName.equals("jsnap")) {
 123             return jsnapHelp();
 124         }
 125         if (toolName.equals("debugd")) {
 126             return debugdHelp();
 127         }
 128         if (toolName.equals("hsdb") || toolName.equals("clhsdb")) {
 129             return commonHelp();
 130         }
 131         return launcherHelp();
 132     }
 133 
 134     private static void buildAttachArgs(ArrayList<String> newArgs, String pid,
 135                                   String exe, String core, boolean allowEmpty) {
 136         if (!allowEmpty && (pid == null) && (exe == null)) {
 137             throw new SAGetoptException("You have to set --pid or --exe.");
 138         }
 139 
 140         if (pid != null) { // Attach to live process
 141             if (exe != null) {
 142                 throw new SAGetoptException("Unnecessary argument: --exe");
 143             } else if (core != null) {
 144                 throw new SAGetoptException("Unnecessary argument: --core");
 145             } else if (!pid.matches("^\\d+$")) {
 146                 throw new SAGetoptException("Invalid pid: " + pid);
 147             }
 148 
 149             newArgs.add(pid);
 150         } else if (exe != null) {
 151             if (exe.length() == 0) {
 152                 throw new SAGetoptException("You have to set --exe.");
 153             }
 154 
 155             newArgs.add(exe);
 156 
 157             if ((core == null) || (core.length() == 0)) {
 158                 throw new SAGetoptException("You have to set --core.");
 159             }
 160 
 161             newArgs.add(core);
 162         }
 163     }
 164 
 165     private static void runCLHSDB(String[] oldArgs) {
 166         SAGetopt sg = new SAGetopt(oldArgs);
 167         String[] longOpts = {"exe=", "core=", "pid="};
 168 
 169         ArrayList<String> newArgs = new ArrayList();
 170         String pid = null;
 171         String exe = null;
 172         String core = null;
 173         String s = null;
 174 
 175         while((s = sg.next(null, longOpts)) != null) {
 176             if (s.equals("exe")) {
 177                 exe = sg.getOptarg();
 178                 continue;
 179             }
 180             if (s.equals("core")) {
 181                 core = sg.getOptarg();
 182                 continue;
 183             }
 184             if (s.equals("pid")) {
 185                 pid = sg.getOptarg();
 186                 continue;
 187             }
 188         }
 189 
 190         buildAttachArgs(newArgs, pid, exe, core, true);
 191         CLHSDB.main(newArgs.toArray(new String[newArgs.size()]));
 192     }
 193 
 194     private static void runHSDB(String[] oldArgs) {
 195         SAGetopt sg = new SAGetopt(oldArgs);
 196         String[] longOpts = {"exe=", "core=", "pid="};
 197 
 198         ArrayList<String> newArgs = new ArrayList();
 199         String pid = null;
 200         String exe = null;
 201         String core = null;
 202         String s = null;
 203 
 204         while((s = sg.next(null, longOpts)) != null) {
 205             if (s.equals("exe")) {
 206                 exe = sg.getOptarg();
 207                 continue;
 208             }
 209             if (s.equals("core")) {
 210                 core = sg.getOptarg();
 211                 continue;
 212             }
 213             if (s.equals("pid")) {
 214                 pid = sg.getOptarg();
 215                 continue;
 216             }
 217         }
 218 
 219         buildAttachArgs(newArgs, pid, exe, core, true);
 220         HSDB.main(newArgs.toArray(new String[newArgs.size()]));
 221     }
 222 
 223     private static void runJSTACK(String[] oldArgs) {
 224         SAGetopt sg = new SAGetopt(oldArgs);
 225         String[] longOpts = {"exe=", "core=", "pid=",
 226                                  "mixed", "locks"};
 227 
 228         ArrayList<String> newArgs = new ArrayList();
 229         String pid = null;
 230         String exe = null;
 231         String core = null;
 232         String s = null;
 233 
 234         while((s = sg.next(null, longOpts)) != null) {
 235             if (s.equals("exe")) {
 236                 exe = sg.getOptarg();
 237                 continue;
 238             }
 239             if (s.equals("core")) {
 240                 core = sg.getOptarg();
 241                 continue;
 242             }
 243             if (s.equals("pid")) {
 244                 pid = sg.getOptarg();
 245                 continue;
 246             }
 247             if (s.equals("mixed")) {
 248                 newArgs.add("-m");
 249                 continue;
 250             }
 251             if (s.equals("locks")) {
 252                 newArgs.add("-l");
 253                 continue;
 254             }
 255         }
 256 
 257         buildAttachArgs(newArgs, pid, exe, core, false);
 258         JStack jstack = new JStack(false, false);
 259         jstack.runWithArgs(newArgs.toArray(new String[newArgs.size()]));
 260     }
 261 
 262     private static void runJMAP(String[] oldArgs) {
 263         SAGetopt sg = new SAGetopt(oldArgs);
 264         String[] longOpts = {"exe=", "core=", "pid=",
 265               "heap", "binaryheap", "dumpfile=", "histo", "clstats", "finalizerinfo"};
 266 
 267         ArrayList<String> newArgs = new ArrayList();
 268         String pid = null;
 269         String exe = null;
 270         String core = null;
 271         String s = null;
 272         String dumpfile = null;
 273         boolean requestHeapdump = false;
 274 
 275         while((s = sg.next(null, longOpts)) != null) {
 276             if (s.equals("exe")) {
 277                 exe = sg.getOptarg();
 278                 continue;
 279             }
 280             if (s.equals("core")) {
 281                 core = sg.getOptarg();
 282                 continue;
 283             }
 284             if (s.equals("pid")) {
 285                 pid = sg.getOptarg();
 286                 continue;
 287             }
 288             if (s.equals("heap")) {
 289                 newArgs.add("-heap");
 290                 continue;
 291             }
 292             if (s.equals("binaryheap")) {
 293                 requestHeapdump = true;
 294                 continue;
 295             }
 296             if (s.equals("dumpfile")) {
 297                 dumpfile = sg.getOptarg();
 298                 continue;
 299             }
 300             if (s.equals("histo")) {
 301                 newArgs.add("-histo");
 302                 continue;
 303             }
 304             if (s.equals("clstats")) {
 305                 newArgs.add("-clstats");
 306                 continue;
 307             }
 308             if (s.equals("finalizerinfo")) {
 309                 newArgs.add("-finalizerinfo");
 310                 continue;
 311             }
 312         }
 313 
 314         if (!requestHeapdump && (dumpfile != null)) {
 315             throw new IllegalArgumentException("Unexpected argument dumpfile");
 316         }
 317         if (requestHeapdump) {
 318             if (dumpfile == null) {
 319                 newArgs.add("-heap:format=b");
 320             } else {
 321                 newArgs.add("-heap:format=b,file=" + dumpfile);
 322             }
 323         }
 324 
 325         buildAttachArgs(newArgs, pid, exe, core, false);
 326         JMap.main(newArgs.toArray(new String[newArgs.size()]));
 327     }
 328 
 329     private static void runJINFO(String[] oldArgs) {
 330         SAGetopt sg = new SAGetopt(oldArgs);
 331         String[] longOpts = {"exe=", "core=", "pid=",
 332                                      "flags", "sysprops"};
 333 
 334         ArrayList<String> newArgs = new ArrayList();
 335         String exe = null;
 336         String pid = null;
 337         String core = null;
 338         String s = null;
 339 
 340         while((s = sg.next(null, longOpts)) != null) {
 341             if (s.equals("exe")) {
 342                 exe = sg.getOptarg();
 343                 continue;
 344             }
 345             if (s.equals("core")) {
 346                 core = sg.getOptarg();
 347                 continue;
 348             }
 349             if (s.equals("pid")) {
 350                 pid = sg.getOptarg();
 351                 continue;
 352             }
 353             if (s.equals("flags")) {
 354                 newArgs.add("-flags");
 355                 continue;
 356             }
 357             if (s.equals("sysprops")) {
 358                 newArgs.add("-sysprops");
 359                 continue;
 360             }
 361         }
 362 
 363         buildAttachArgs(newArgs, pid, exe, core, false);
 364         JInfo.main(newArgs.toArray(new String[newArgs.size()]));
 365     }
 366 
 367     private static void runJSNAP(String[] oldArgs) {
 368         SAGetopt sg = new SAGetopt(oldArgs);
 369         String[] longOpts = {"exe=", "core=", "pid=", "all"};
 370 
 371         ArrayList<String> newArgs = new ArrayList();
 372         String exe = null;
 373         String pid = null;
 374         String core = null;
 375         String s = null;
 376 
 377         while((s = sg.next(null, longOpts)) != null) {
 378             if (s.equals("exe")) {
 379                 exe = sg.getOptarg();
 380                 continue;
 381             }
 382             if (s.equals("core")) {
 383                 core = sg.getOptarg();
 384                 continue;
 385             }
 386             if (s.equals("pid")) {
 387                 pid = sg.getOptarg();
 388                 continue;
 389             }
 390             if (s.equals("all")) {
 391                 newArgs.add("-a");
 392                 continue;
 393             }
 394         }
 395 
 396         buildAttachArgs(newArgs, pid, exe, core, false);
 397         JSnap.main(newArgs.toArray(new String[newArgs.size()]));
 398     }
 399 
 400     private static void runDEBUGD(String[] oldArgs) {
 401         if ((oldArgs.length < 1) || (oldArgs.length > 3)) {
 402             debugdHelp();
 403         }
 404 
 405         // By default SA agent classes prefer Windows process debugger
 406         // to windbg debugger. SA expects special properties to be set
 407         // to choose other debuggers. We will set those here before
 408         // attaching to SA agent.
 409         System.setProperty("sun.jvm.hotspot.debugger.useWindbgDebugger", "true");
 410 
 411         // delegate to the actual SA debug server.
 412         sun.jvm.hotspot.DebugServer.main(oldArgs);
 413     }
 414 
 415     public static void main(String[] args) {
 416         // Provide a help
 417         if (args.length == 0) {
 418             launcherHelp();
 419             return;
 420         }
 421         // No arguments imply help for debugd, jstack, jmap, jinfo but launch clhsdb and hsdb
 422         if (args.length == 1 && !args[0].equals("clhsdb") && !args[0].equals("hsdb")) {
 423             toolHelp(args[0]);
 424             return;
 425         }
 426 
 427         for (String arg : args) {
 428             if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help")) {
 429                 toolHelp(args[0]);
 430                 return;
 431             }
 432         }
 433 
 434         String[] oldArgs = Arrays.copyOfRange(args, 1, args.length);
 435 
 436         try {
 437             // Run SA interactive mode
 438             if (args[0].equals("clhsdb")) {
 439                 runCLHSDB(oldArgs);
 440                 return;
 441             }
 442 
 443             if (args[0].equals("hsdb")) {
 444                 runHSDB(oldArgs);
 445                 return;
 446             }
 447 
 448             // Run SA tmtools mode
 449             if (args[0].equals("jstack")) {
 450                 runJSTACK(oldArgs);
 451                 return;
 452             }
 453 
 454             if (args[0].equals("jmap")) {
 455                 runJMAP(oldArgs);
 456                 return;
 457             }
 458 
 459             if (args[0].equals("jinfo")) {
 460                 runJINFO(oldArgs);
 461                 return;
 462             }
 463 
 464             if (args[0].equals("jsnap")) {
 465                 runJSNAP(oldArgs);
 466                 return;
 467             }
 468 
 469             if (args[0].equals("debugd")) {
 470                 runDEBUGD(oldArgs);
 471                 return;
 472             }
 473 
 474             throw new SAGetoptException("Unknown tool: " + args[0]);
 475         } catch (SAGetoptException e) {
 476             System.err.println(e.getMessage());
 477             toolHelp(args[0]);
 478         }
 479     }
 480 }