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