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