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