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