Showing the changes to java/pkg/com/sun/tools/example/debug/tty/TTY.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,1063 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1998, 2008, 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. Oracle designates this | ||
| 8 | * particular file as subject to the "Classpath" exception as provided | ||
| 9 | * by Oracle in the LICENSE file that accompanied this code. | ||
| 10 | * | ||
| 11 | * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 14 | * version 2 for more details (a copy is included in the LICENSE file that | ||
| 15 | * accompanied this code). | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License version | ||
| 18 | * 2 along with this work; if not, write to the Free Software Foundation, | ||
| 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 20 | * | ||
| 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| 22 | * or visit www.oracle.com if you need additional information or have any | ||
| 23 | * questions. | ||
| 24 | */ | ||
| 25 | |||
| 26 | package com.sun.tools.example.debug.tty; | ||
| 27 | |||
| 28 | import com.sun.jdi.*; | ||
| 29 | import com.sun.jdi.event.*; | ||
| 30 | import com.sun.jdi.request.*; | ||
| 31 | import com.sun.jdi.connect.*; | ||
| 32 | |||
| 33 | import java.util.*; | ||
| 34 | import java.io.*; | ||
| 35 | |||
| 36 | public class TTY implements EventNotifier { | ||
| 37 | EventHandler handler = null; | ||
| 38 | |||
| 39 | /** | ||
| 40 | * List of Strings to execute at each stop. | ||
| 41 | */ | ||
| 42 | private List<String> monitorCommands = new ArrayList<String>(); | ||
| 43 | private int monitorCount = 0; | ||
| 44 | |||
| 45 | /** | ||
| 46 | * The name of this tool. | ||
| 47 | */ | ||
| 48 | private static final String progname = "jdb"; | ||
| 49 | |||
| 50 | @Override | ||
| 51 | public void vmStartEvent(VMStartEvent se) { | ||
| 52 | Thread.yield(); // fetch output | ||
| 53 | MessageOutput.lnprint("VM Started:"); | ||
| 54 | } | ||
| 55 | |||
| 56 | @Override | ||
| 57 | public void vmDeathEvent(VMDeathEvent e) { | ||
| 58 | } | ||
| 59 | |||
| 60 | @Override | ||
| 61 | public void vmDisconnectEvent(VMDisconnectEvent e) { | ||
| 62 | } | ||
| 63 | |||
| 64 | @Override | ||
| 65 | public void threadStartEvent(ThreadStartEvent e) { | ||
| 66 | } | ||
| 67 | |||
| 68 | @Override | ||
| 69 | public void threadDeathEvent(ThreadDeathEvent e) { | ||
| 70 | } | ||
| 71 | |||
| 72 | @Override | ||
| 73 | public void classPrepareEvent(ClassPrepareEvent e) { | ||
| 74 | } | ||
| 75 | |||
| 76 | @Override | ||
| 77 | public void classUnloadEvent(ClassUnloadEvent e) { | ||
| 78 | } | ||
| 79 | |||
| 80 | @Override | ||
| 81 | public void breakpointEvent(BreakpointEvent be) { | ||
| 82 | Thread.yield(); // fetch output | ||
| 83 | MessageOutput.lnprint("Breakpoint hit:"); | ||
| 84 | } | ||
| 85 | |||
| 86 | @Override | ||
| 87 | public void fieldWatchEvent(WatchpointEvent fwe) { | ||
| 88 | Field field = fwe.field(); | ||
| 89 | ObjectReference obj = fwe.object(); | ||
| 90 | Thread.yield(); // fetch output | ||
| 91 | |||
| 92 | if (fwe instanceof ModificationWatchpointEvent) { | ||
| 93 | MessageOutput.lnprint("Field access encountered before after", | ||
| 94 | new Object [] {field, | ||
| 95 | fwe.valueCurrent(), | ||
| 96 | ((ModificationWatchpointEvent)fwe).valueToBe()}); | ||
| 97 | } else { | ||
| 98 | MessageOutput.lnprint("Field access encountered", field.toString()); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | @Override | ||
| 103 | public void stepEvent(StepEvent se) { | ||
| 104 | Thread.yield(); // fetch output | ||
| 105 | MessageOutput.lnprint("Step completed:"); | ||
| 106 | } | ||
| 107 | |||
| 108 | @Override | ||
| 109 | public void exceptionEvent(ExceptionEvent ee) { | ||
| 110 | Thread.yield(); // fetch output | ||
| 111 | Location catchLocation = ee.catchLocation(); | ||
| 112 | if (catchLocation == null) { | ||
| 113 | MessageOutput.lnprint("Exception occurred uncaught", | ||
| 114 | ee.exception().referenceType().name()); | ||
| 115 | } else { | ||
| 116 | MessageOutput.lnprint("Exception occurred caught", | ||
| 117 | new Object [] {ee.exception().referenceType().name(), | ||
| 118 | Commands.locationString(catchLocation)}); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | @Override | ||
| 123 | public void methodEntryEvent(MethodEntryEvent me) { | ||
| 124 | Thread.yield(); // fetch output | ||
| 125 | /* | ||
| 126 | * These can be very numerous, so be as efficient as possible. | ||
| 127 | * If we are stopping here, then we will see the normal location | ||
| 128 | * info printed. | ||
| 129 | */ | ||
| 130 | if (me.request().suspendPolicy() != EventRequest.SUSPEND_NONE) { | ||
| 131 | // We are stopping; the name will be shown by the normal mechanism | ||
| 132 | MessageOutput.lnprint("Method entered:"); | ||
| 133 | } else { | ||
| 134 | // We aren't stopping, show the name | ||
| 135 | MessageOutput.print("Method entered:"); | ||
| 136 | printLocationOfEvent(me); | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | @Override | ||
| 141 | public boolean methodExitEvent(MethodExitEvent me) { | ||
| 142 | Thread.yield(); // fetch output | ||
| 143 | /* | ||
| 144 | * These can be very numerous, so be as efficient as possible. | ||
| 145 | */ | ||
| 146 | Method mmm = Env.atExitMethod(); | ||
| 147 | Method meMethod = me.method(); | ||
| 148 | |||
| 149 | if (mmm == null || mmm.equals(meMethod)) { | ||
| 150 | // Either we are not tracing a specific method, or we are | ||
| 151 | // and we are exitting that method. | ||
| 152 | |||
| 153 | if (me.request().suspendPolicy() != EventRequest.SUSPEND_NONE) { | ||
| 154 | // We will be stopping here, so do a newline | ||
| 155 | MessageOutput.println(); | ||
| 156 | } | ||
| 157 | if (Env.vm().canGetMethodReturnValues()) { | ||
| 158 | MessageOutput.print("Method exitedValue:", me.returnValue() + ""); | ||
| 159 | } else { | ||
| 160 | MessageOutput.print("Method exited:"); | ||
| 161 | } | ||
| 162 | |||
| 163 | if (me.request().suspendPolicy() == EventRequest.SUSPEND_NONE) { | ||
| 164 | // We won't be stopping here, so show the method name | ||
| 165 | printLocationOfEvent(me); | ||
| 166 | |||
| 167 | } | ||
| 168 | |||
| 169 | // In case we want to have a one shot trace exit some day, this | ||
| 170 | // code disables the request so we don't hit it again. | ||
| 171 | if (false) { | ||
| 172 | // This is a one shot deal; we don't want to stop | ||
| 173 | // here the next time. | ||
| 174 | Env.setAtExitMethod(null); | ||
| 175 | EventRequestManager erm = Env.vm().eventRequestManager(); | ||
| 176 | for (EventRequest eReq : erm.methodExitRequests()) { | ||
| 177 | if (eReq.equals(me.request())) { | ||
| 178 | eReq.disable(); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | } | ||
| 182 | return true; | ||
| 183 | } | ||
| 184 | |||
| 185 | // We are tracing a specific method, and this isn't it. Keep going. | ||
| 186 | return false; | ||
| 187 | } | ||
| 188 | |||
| 189 | @Override | ||
| 190 | public void vmInterrupted() { | ||
| 191 | Thread.yield(); // fetch output | ||
| 192 | printCurrentLocation(); | ||
| 193 | for (String cmd : monitorCommands) { | ||
| 194 | StringTokenizer t = new StringTokenizer(cmd); | ||
| 195 | t.nextToken(); // get rid of monitor number | ||
| 196 | executeCommand(t); | ||
| 197 | } | ||
| 198 | MessageOutput.printPrompt(); | ||
| 199 | } | ||
| 200 | |||
| 201 | @Override | ||
| 202 | public void receivedEvent(Event event) { | ||
| 203 | } | ||
| 204 | |||
| 205 | private void printBaseLocation(String threadName, Location loc) { | ||
| 206 | MessageOutput.println("location", | ||
| 207 | new Object [] {threadName, | ||
| 208 | Commands.locationString(loc)}); | ||
| 209 | } | ||
| 210 | |||
| 211 | private void printCurrentLocation() { | ||
| 212 | ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); | ||
| 213 | StackFrame frame; | ||
| 214 | try { | ||
| 215 | frame = threadInfo.getCurrentFrame(); | ||
| 216 | } catch (IncompatibleThreadStateException exc) { | ||
| 217 | MessageOutput.println("<location unavailable>"); | ||
| 218 | return; | ||
| 219 | } | ||
| 220 | if (frame == null) { | ||
| 221 | MessageOutput.println("No frames on the current call stack"); | ||
| 222 | } else { | ||
| 223 | Location loc = frame.location(); | ||
| 224 | printBaseLocation(threadInfo.getThread().name(), loc); | ||
| 225 | // Output the current source line, if possible | ||
| 226 | if (loc.lineNumber() != -1) { | ||
| 227 | String line; | ||
| 228 | try { | ||
| 229 | line = Env.sourceLine(loc, loc.lineNumber()); | ||
| 230 | } catch (java.io.IOException e) { | ||
| 231 | line = null; | ||
| 232 | } | ||
| 233 | if (line != null) { | ||
| 234 | MessageOutput.println("source line number and line", | ||
| 235 | new Object [] {new Integer(loc.lineNumber()), | ||
| 236 | line}); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | } | ||
| 240 | MessageOutput.println(); | ||
| 241 | } | ||
| 242 | |||
| 243 | private void printLocationOfEvent(LocatableEvent theEvent) { | ||
| 244 | printBaseLocation(theEvent.thread().name(), theEvent.location()); | ||
| 245 | } | ||
| 246 | |||
| 247 | void help() { | ||
| 248 | MessageOutput.println("zz help text"); | ||
| 249 | } | ||
| 250 | |||
| 251 | private static final String[][] commandList = { | ||
| 252 | /* | ||
| 253 | * NOTE: this list must be kept sorted in ascending ASCII | ||
| 254 | * order by element [0]. Ref: isCommand() below. | ||
| 255 | * | ||
| 256 | *Command OK when OK when | ||
| 257 | * name disconnected? readonly? | ||
| 258 | *------------------------------------ | ||
| 259 | */ | ||
| 260 | {"!!", "n", "y"}, | ||
| 261 | {"?", "y", "y"}, | ||
| 262 | {"bytecodes", "n", "y"}, | ||
| 263 | {"catch", "y", "n"}, | ||
| 264 | {"class", "n", "y"}, | ||
| 265 | {"classes", "n", "y"}, | ||
| 266 | {"classpath", "n", "y"}, | ||
| 267 | {"clear", "y", "n"}, | ||
| 268 | {"connectors", "y", "y"}, | ||
| 269 | {"cont", "n", "n"}, | ||
| 270 | {"disablegc", "n", "n"}, | ||
| 271 | {"down", "n", "y"}, | ||
| 272 | {"dump", "n", "y"}, | ||
| 273 | {"enablegc", "n", "n"}, | ||
| 274 | {"eval", "n", "y"}, | ||
| 275 | {"exclude", "y", "n"}, | ||
| 276 | {"exit", "y", "y"}, | ||
| 277 | {"extension", "n", "y"}, | ||
| 278 | {"fields", "n", "y"}, | ||
| 279 | {"gc", "n", "n"}, | ||
| 280 | {"help", "y", "y"}, | ||
| 281 | {"ignore", "y", "n"}, | ||
| 282 | {"interrupt", "n", "n"}, | ||
| 283 | {"kill", "n", "n"}, | ||
| 284 | {"lines", "n", "y"}, | ||
| 285 | {"list", "n", "y"}, | ||
| 286 | {"load", "n", "y"}, | ||
| 287 | {"locals", "n", "y"}, | ||
| 288 | {"lock", "n", "n"}, | ||
| 289 | {"memory", "n", "y"}, | ||
| 290 | {"methods", "n", "y"}, | ||
| 291 | {"monitor", "n", "n"}, | ||
| 292 | {"next", "n", "n"}, | ||
| 293 | {"pop", "n", "n"}, | ||
| 294 | {"print", "n", "y"}, | ||
| 295 | {"quit", "y", "y"}, | ||
| 296 | {"read", "y", "y"}, | ||
| 297 | {"redefine", "n", "n"}, | ||
| 298 | {"reenter", "n", "n"}, | ||
| 299 | {"resume", "n", "n"}, | ||
| 300 | {"run", "y", "n"}, | ||
| 301 | {"save", "n", "n"}, | ||
| 302 | {"set", "n", "n"}, | ||
| 303 | {"sourcepath", "y", "y"}, | ||
| 304 | {"step", "n", "n"}, | ||
| 305 | {"stepi", "n", "n"}, | ||
| 306 | {"stop", "y", "n"}, | ||
| 307 | {"suspend", "n", "n"}, | ||
| 308 | {"thread", "n", "y"}, | ||
| 309 | {"threadgroup", "n", "y"}, | ||
| 310 | {"threadgroups", "n", "y"}, | ||
| 311 | {"threadlocks", "n", "y"}, | ||
| 312 | {"threads", "n", "y"}, | ||
| 313 | {"trace", "n", "n"}, | ||
| 314 | {"unmonitor", "n", "n"}, | ||
| 315 | {"untrace", "n", "n"}, | ||
| 316 | {"unwatch", "y", "n"}, | ||
| 317 | {"up", "n", "y"}, | ||
| 318 | {"use", "y", "y"}, | ||
| 319 | {"version", "y", "y"}, | ||
| 320 | {"watch", "y", "n"}, | ||
| 321 | {"where", "n", "y"}, | ||
| 322 | {"wherei", "n", "y"}, | ||
| 323 | }; | ||
| 324 | |||
| 325 | /* | ||
| 326 | * Look up the command string in commandList. | ||
| 327 | * If found, return the index. | ||
| 328 | * If not found, return index < 0 | ||
| 329 | */ | ||
| 330 | private int isCommand(String key) { | ||
| 331 | //Reference: binarySearch() in java/util/Arrays.java | ||
| 332 | // Adapted for use with String[][0]. | ||
| 333 | int low = 0; | ||
| 334 | int high = commandList.length - 1; | ||
| 335 | while (low <= high) { | ||
| 336 | int mid = (low + high) >>> 1; | ||
| 337 | String midVal = commandList[mid][0]; | ||
| 338 | int compare = midVal.compareTo(key); | ||
| 339 | if (compare < 0) { | ||
| 340 | low = mid + 1; | ||
| 341 | } else if (compare > 0) { | ||
| 342 | high = mid - 1; | ||
| 343 | } | ||
| 344 | else { | ||
| 345 | return mid; // key found | ||
| 346 | } | ||
| 347 | } | ||
| 348 | return -(low + 1); // key not found. | ||
| 349 | }; | ||
| 350 | |||
| 351 | /* | ||
| 352 | * Return true if the command is OK when disconnected. | ||
| 353 | */ | ||
| 354 | private boolean isDisconnectCmd(int ii) { | ||
| 355 | if (ii < 0 || ii >= commandList.length) { | ||
| 356 | return false; | ||
| 357 | } | ||
| 358 | return (commandList[ii][1].equals("y")); | ||
| 359 | } | ||
| 360 | |||
| 361 | /* | ||
| 362 | * Return true if the command is OK when readonly. | ||
| 363 | */ | ||
| 364 | private boolean isReadOnlyCmd(int ii) { | ||
| 365 | if (ii < 0 || ii >= commandList.length) { | ||
| 366 | return false; | ||
| 367 | } | ||
| 368 | return (commandList[ii][2].equals("y")); | ||
| 369 | }; | ||
| 370 | |||
| 371 | |||
| 372 | void executeCommand(StringTokenizer t) { | ||
| 373 | String cmd = t.nextToken().toLowerCase(); | ||
| 374 | // Normally, prompt for the next command after this one is done | ||
| 375 | boolean showPrompt = true; | ||
| 376 | |||
| 377 | |||
| 378 | /* | ||
| 379 | * Anything starting with # is discarded as a no-op or 'comment'. | ||
| 380 | */ | ||
| 381 | if (!cmd.startsWith("#")) { | ||
| 382 | /* | ||
| 383 | * Next check for an integer repetition prefix. If found, | ||
| 384 | * recursively execute cmd that number of times. | ||
| 385 | */ | ||
| 386 | if (Character.isDigit(cmd.charAt(0)) && t.hasMoreTokens()) { | ||
| 387 | try { | ||
| 388 | int repeat = Integer.parseInt(cmd); | ||
| 389 | String subcom = t.nextToken(""); | ||
| 390 | while (repeat-- > 0) { | ||
| 391 | executeCommand(new StringTokenizer(subcom)); | ||
| 392 | showPrompt = false; // Bypass the printPrompt() below. | ||
| 393 | } | ||
| 394 | } catch (NumberFormatException exc) { | ||
| 395 | MessageOutput.println("Unrecognized command. Try help...", cmd); | ||
| 396 | } | ||
| 397 | } else { | ||
| 398 | int commandNumber = isCommand(cmd); | ||
| 399 | /* | ||
| 400 | * Check for an unknown command | ||
| 401 | */ | ||
| 402 | if (commandNumber < 0) { | ||
| 403 | MessageOutput.println("Unrecognized command. Try help...", cmd); | ||
| 404 | } else if (!Env.connection().isOpen() && !isDisconnectCmd(commandNumber)) { | ||
| 405 | MessageOutput.println("Command not valid until the VM is started with the run command", | ||
| 406 | cmd); | ||
| 407 | } else if (Env.connection().isOpen() && !Env.vm().canBeModified() && | ||
| 408 | !isReadOnlyCmd(commandNumber)) { | ||
| 409 | MessageOutput.println("Command is not supported on a read-only VM connection", | ||
| 410 | cmd); | ||
| 411 | } else { | ||
| 412 | |||
| 413 | Commands evaluator = new Commands(); | ||
| 414 | try { | ||
| 415 | if (cmd.equals("print")) { | ||
| 416 | evaluator.commandPrint(t, false); | ||
| 417 | showPrompt = false; // asynchronous command | ||
| 418 | } else if (cmd.equals("eval")) { | ||
| 419 | evaluator.commandPrint(t, false); | ||
| 420 | showPrompt = false; // asynchronous command | ||
| 421 | } else if (cmd.equals("set")) { | ||
| 422 | evaluator.commandSet(t); | ||
| 423 | showPrompt = false; // asynchronous command | ||
| 424 | } else if (cmd.equals("dump")) { | ||
| 425 | evaluator.commandPrint(t, true); | ||
| 426 | showPrompt = false; // asynchronous command | ||
| 427 | } else if (cmd.equals("locals")) { | ||
| 428 | evaluator.commandLocals(); | ||
| 429 | } else if (cmd.equals("classes")) { | ||
| 430 | evaluator.commandClasses(); | ||
| 431 | } else if (cmd.equals("class")) { | ||
| 432 | evaluator.commandClass(t); | ||
| 433 | } else if (cmd.equals("connectors")) { | ||
| 434 | evaluator.commandConnectors(Bootstrap.virtualMachineManager()); | ||
| 435 | } else if (cmd.equals("methods")) { | ||
| 436 | evaluator.commandMethods(t); | ||
| 437 | } else if (cmd.equals("fields")) { | ||
| 438 | evaluator.commandFields(t); | ||
| 439 | } else if (cmd.equals("threads")) { | ||
| 440 | evaluator.commandThreads(t); | ||
| 441 | } else if (cmd.equals("thread")) { | ||
| 442 | evaluator.commandThread(t); | ||
| 443 | } else if (cmd.equals("suspend")) { | ||
| 444 | evaluator.commandSuspend(t); | ||
| 445 | } else if (cmd.equals("resume")) { | ||
| 446 | evaluator.commandResume(t); | ||
| 447 | } else if (cmd.equals("cont")) { | ||
| 448 | evaluator.commandCont(); | ||
| 449 | } else if (cmd.equals("threadgroups")) { | ||
| 450 | evaluator.commandThreadGroups(); | ||
| 451 | } else if (cmd.equals("threadgroup")) { | ||
| 452 | evaluator.commandThreadGroup(t); | ||
| 453 | } else if (cmd.equals("catch")) { | ||
| 454 | evaluator.commandCatchException(t); | ||
| 455 | } else if (cmd.equals("ignore")) { | ||
| 456 | evaluator.commandIgnoreException(t); | ||
| 457 | } else if (cmd.equals("step")) { | ||
| 458 | evaluator.commandStep(t); | ||
| 459 | } else if (cmd.equals("stepi")) { | ||
| 460 | evaluator.commandStepi(); | ||
| 461 | } else if (cmd.equals("next")) { | ||
| 462 | evaluator.commandNext(); | ||
| 463 | } else if (cmd.equals("kill")) { | ||
| 464 | evaluator.commandKill(t); | ||
| 465 | } else if (cmd.equals("interrupt")) { | ||
| 466 | evaluator.commandInterrupt(t); | ||
| 467 | } else if (cmd.equals("trace")) { | ||
| 468 | evaluator.commandTrace(t); | ||
| 469 | } else if (cmd.equals("untrace")) { | ||
| 470 | evaluator.commandUntrace(t); | ||
| 471 | } else if (cmd.equals("where")) { | ||
| 472 | evaluator.commandWhere(t, false); | ||
| 473 | } else if (cmd.equals("wherei")) { | ||
| 474 | evaluator.commandWhere(t, true); | ||
| 475 | } else if (cmd.equals("up")) { | ||
| 476 | evaluator.commandUp(t); | ||
| 477 | } else if (cmd.equals("down")) { | ||
| 478 | evaluator.commandDown(t); | ||
| 479 | } else if (cmd.equals("load")) { | ||
| 480 | evaluator.commandLoad(t); | ||
| 481 | } else if (cmd.equals("run")) { | ||
| 482 | evaluator.commandRun(t); | ||
| 483 | /* | ||
| 484 | * Fire up an event handler, if the connection was just | ||
| 485 | * opened. Since this was done from the run command | ||
| 486 | * we don't stop the VM on its VM start event (so | ||
| 487 | * arg 2 is false). | ||
| 488 | */ | ||
| 489 | if ((handler == null) && Env.connection().isOpen()) { | ||
| 490 | handler = new EventHandler(this, false); | ||
| 491 | } | ||
| 492 | } else if (cmd.equals("memory")) { | ||
| 493 | evaluator.commandMemory(); | ||
| 494 | } else if (cmd.equals("gc")) { | ||
| 495 | evaluator.commandGC(); | ||
| 496 | } else if (cmd.equals("stop")) { | ||
| 497 | evaluator.commandStop(t); | ||
| 498 | } else if (cmd.equals("clear")) { | ||
| 499 | evaluator.commandClear(t); | ||
| 500 | } else if (cmd.equals("watch")) { | ||
| 501 | evaluator.commandWatch(t); | ||
| 502 | } else if (cmd.equals("unwatch")) { | ||
| 503 | evaluator.commandUnwatch(t); | ||
| 504 | } else if (cmd.equals("list")) { | ||
| 505 | evaluator.commandList(t); | ||
| 506 | } else if (cmd.equals("lines")) { // Undocumented command: useful for testing. | ||
| 507 | evaluator.commandLines(t); | ||
| 508 | } else if (cmd.equals("classpath")) { | ||
| 509 | evaluator.commandClasspath(t); | ||
| 510 | } else if (cmd.equals("use") || cmd.equals("sourcepath")) { | ||
| 511 | evaluator.commandUse(t); | ||
| 512 | } else if (cmd.equals("monitor")) { | ||
| 513 | monitorCommand(t); | ||
| 514 | } else if (cmd.equals("unmonitor")) { | ||
| 515 | unmonitorCommand(t); | ||
| 516 | } else if (cmd.equals("lock")) { | ||
| 517 | evaluator.commandLock(t); | ||
| 518 | showPrompt = false; // asynchronous command | ||
| 519 | } else if (cmd.equals("threadlocks")) { | ||
| 520 | evaluator.commandThreadlocks(t); | ||
| 521 | } else if (cmd.equals("disablegc")) { | ||
| 522 | evaluator.commandDisableGC(t); | ||
| 523 | showPrompt = false; // asynchronous command | ||
| 524 | } else if (cmd.equals("enablegc")) { | ||
| 525 | evaluator.commandEnableGC(t); | ||
| 526 | showPrompt = false; // asynchronous command | ||
| 527 | } else if (cmd.equals("save")) { // Undocumented command: useful for testing. | ||
| 528 | evaluator.commandSave(t); | ||
| 529 | showPrompt = false; // asynchronous command | ||
| 530 | } else if (cmd.equals("bytecodes")) { // Undocumented command: useful for testing. | ||
| 531 | evaluator.commandBytecodes(t); | ||
| 532 | } else if (cmd.equals("redefine")) { | ||
| 533 | evaluator.commandRedefine(t); | ||
| 534 | } else if (cmd.equals("pop")) { | ||
| 535 | evaluator.commandPopFrames(t, false); | ||
| 536 | } else if (cmd.equals("reenter")) { | ||
| 537 | evaluator.commandPopFrames(t, true); | ||
| 538 | } else if (cmd.equals("extension")) { | ||
| 539 | evaluator.commandExtension(t); | ||
| 540 | } else if (cmd.equals("exclude")) { | ||
| 541 | evaluator.commandExclude(t); | ||
| 542 | } else if (cmd.equals("read")) { | ||
| 543 | readCommand(t); | ||
| 544 | } else if (cmd.equals("help") || cmd.equals("?")) { | ||
| 545 | help(); | ||
| 546 | } else if (cmd.equals("version")) { | ||
| 547 | evaluator.commandVersion(progname, | ||
| 548 | Bootstrap.virtualMachineManager()); | ||
| 549 | } else if (cmd.equals("quit") || cmd.equals("exit")) { | ||
| 550 | if (handler != null) { | ||
| 551 | handler.shutdown(); | ||
| 552 | } | ||
| 553 | Env.shutdown(); | ||
| 554 | } else { | ||
| 555 | MessageOutput.println("Unrecognized command. Try help...", cmd); | ||
| 556 | } | ||
| 557 | } catch (VMCannotBeModifiedException rovm) { | ||
| 558 | MessageOutput.println("Command is not supported on a read-only VM connection", cmd); | ||
| 559 | } catch (UnsupportedOperationException uoe) { | ||
| 560 | MessageOutput.println("Command is not supported on the target VM", cmd); | ||
| 561 | } catch (VMNotConnectedException vmnse) { | ||
| 562 | MessageOutput.println("Command not valid until the VM is started with the run command", | ||
| 563 | cmd); | ||
| 564 | } catch (Exception e) { | ||
| 565 | MessageOutput.printException("Internal exception:", e); | ||
| 566 | } | ||
| 567 | } | ||
| 568 | } | ||
| 569 | } | ||
| 570 | if (showPrompt) { | ||
| 571 | MessageOutput.printPrompt(); | ||
| 572 | } | ||
| 573 | } | ||
| 574 | |||
| 575 | /* | ||
| 576 | * Maintain a list of commands to execute each time the VM is suspended. | ||
| 577 | */ | ||
| 578 | void monitorCommand(StringTokenizer t) { | ||
| 579 | if (t.hasMoreTokens()) { | ||
| 580 | ++monitorCount; | ||
| 581 | monitorCommands.add(monitorCount + ": " + t.nextToken("")); | ||
| 582 | } else { | ||
| 583 | for (String cmd : monitorCommands) { | ||
| 584 | MessageOutput.printDirectln(cmd);// Special case: use printDirectln() | ||
| 585 | } | ||
| 586 | } | ||
| 587 | } | ||
| 588 | |||
| 589 | void unmonitorCommand(StringTokenizer t) { | ||
| 590 | if (t.hasMoreTokens()) { | ||
| 591 | String monTok = t.nextToken(); | ||
| 592 | int monNum; | ||
| 593 | try { | ||
| 594 | monNum = Integer.parseInt(monTok); | ||
| 595 | } catch (NumberFormatException exc) { | ||
| 596 | MessageOutput.println("Not a monitor number:", monTok); | ||
| 597 | return; | ||
| 598 | } | ||
| 599 | String monStr = monTok + ":"; | ||
| 600 | for (String cmd : monitorCommands) { | ||
| 601 | StringTokenizer ct = new StringTokenizer(cmd); | ||
| 602 | if (ct.nextToken().equals(monStr)) { | ||
| 603 | monitorCommands.remove(cmd); | ||
| 604 | MessageOutput.println("Unmonitoring", cmd); | ||
| 605 | return; | ||
| 606 | } | ||
| 607 | } | ||
| 608 | MessageOutput.println("No monitor numbered:", monTok); | ||
| 609 | } else { | ||
| 610 | MessageOutput.println("Usage: unmonitor <monitor#>"); | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | |||
| 615 | void readCommand(StringTokenizer t) { | ||
| 616 | if (t.hasMoreTokens()) { | ||
| 617 | String cmdfname = t.nextToken(); | ||
| 618 | if (!readCommandFile(new File(cmdfname))) { | ||
| 619 | MessageOutput.println("Could not open:", cmdfname); | ||
| 620 | } | ||
| 621 | } else { | ||
| 622 | MessageOutput.println("Usage: read <command-filename>"); | ||
| 623 | } | ||
| 624 | } | ||
| 625 | |||
| 626 | /** | ||
| 627 | * Read and execute a command file. Return true if the file was read | ||
| 628 | * else false; | ||
| 629 | */ | ||
| 630 | boolean readCommandFile(File f) { | ||
| 631 | BufferedReader inFile = null; | ||
| 632 | try { | ||
| 633 | if (f.canRead()) { | ||
| 634 | // Process initial commands. | ||
| 635 | MessageOutput.println("*** Reading commands from", f.getPath()); | ||
| 636 | inFile = new BufferedReader(new FileReader(f)); | ||
| 637 | String ln; | ||
| 638 | while ((ln = inFile.readLine()) != null) { | ||
| 639 | StringTokenizer t = new StringTokenizer(ln); | ||
| 640 | if (t.hasMoreTokens()) { | ||
| 641 | executeCommand(t); | ||
| 642 | } | ||
| 643 | } | ||
| 644 | } | ||
| 645 | } catch (IOException e) { | ||
| 646 | } finally { | ||
| 647 | if (inFile != null) { | ||
| 648 | try { | ||
| 649 | inFile.close(); | ||
| 650 | } catch (Exception exc) { | ||
| 651 | } | ||
| 652 | } | ||
| 653 | } | ||
| 654 | return inFile != null; | ||
| 655 | } | ||
| 656 | |||
| 657 | /** | ||
| 658 | * Try to read commands from dir/fname, unless | ||
| 659 | * the canonical path passed in is the same as that | ||
| 660 | * for dir/fname. | ||
| 661 | * Return null if that file doesn't exist, | ||
| 662 | * else return the canonical path of that file. | ||
| 663 | */ | ||
| 664 | String readStartupCommandFile(String dir, String fname, String canonPath) { | ||
| 665 | File dotInitFile = new File(dir, fname); | ||
| 666 | if (!dotInitFile.exists()) { | ||
| 667 | return null; | ||
| 668 | } | ||
| 669 | |||
| 670 | String myCanonFile; | ||
| 671 | try { | ||
| 672 | myCanonFile = dotInitFile.getCanonicalPath(); | ||
| 673 | } catch (IOException ee) { | ||
| 674 | MessageOutput.println("Could not open:", dotInitFile.getPath()); | ||
| 675 | return null; | ||
| 676 | } | ||
| 677 | if (canonPath == null || !canonPath.equals(myCanonFile)) { | ||
| 678 | if (!readCommandFile(dotInitFile)) { | ||
| 679 | MessageOutput.println("Could not open:", dotInitFile.getPath()); | ||
| 680 | } | ||
| 681 | } | ||
| 682 | return myCanonFile; | ||
| 683 | } | ||
| 684 | |||
| 685 | |||
| 686 | public TTY() throws Exception { | ||
| 687 | |||
| 688 | MessageOutput.println("Initializing progname", progname); | ||
| 689 | |||
| 690 | if (Env.connection().isOpen() && Env.vm().canBeModified()) { | ||
| 691 | /* | ||
| 692 | * Connection opened on startup. Start event handler | ||
| 693 | * immediately, telling it (through arg 2) to stop on the | ||
| 694 | * VM start event. | ||
| 695 | */ | ||
| 696 | this.handler = new EventHandler(this, true); | ||
| 697 | } | ||
| 698 | try { | ||
| 699 | BufferedReader in = | ||
| 700 | new BufferedReader(new InputStreamReader(System.in)); | ||
| 701 | |||
| 702 | String lastLine = null; | ||
| 703 | |||
| 704 | Thread.currentThread().setPriority(Thread.NORM_PRIORITY); | ||
| 705 | |||
| 706 | /* | ||
| 707 | * Read start up files. This mimics the behavior | ||
| 708 | * of gdb which will read both ~/.gdbinit and then | ||
| 709 | * ./.gdbinit if they exist. We have the twist that | ||
| 710 | * we allow two different names, so we do this: | ||
| 711 | * if ~/jdb.ini exists, | ||
| 712 | * read it | ||
| 713 | * else if ~/.jdbrc exists, | ||
| 714 | * read it | ||
| 715 | * | ||
| 716 | * if ./jdb.ini exists, | ||
| 717 | * if it hasn't been read, read it | ||
| 718 | * It could have been read above because ~ == . | ||
| 719 | * or because of symlinks, ... | ||
| 720 | * else if ./jdbrx exists | ||
| 721 | * if it hasn't been read, read it | ||
| 722 | */ | ||
| 723 | { | ||
| 724 | String userHome = System.getProperty("user.home"); | ||
| 725 | String canonPath; | ||
| 726 | |||
| 727 | if ((canonPath = readStartupCommandFile(userHome, "jdb.ini", null)) == null) { | ||
| 728 | // Doesn't exist, try alternate spelling | ||
| 729 | canonPath = readStartupCommandFile(userHome, ".jdbrc", null); | ||
| 730 | } | ||
| 731 | |||
| 732 | String userDir = System.getProperty("user.dir"); | ||
| 733 | if (readStartupCommandFile(userDir, "jdb.ini", canonPath) == null) { | ||
| 734 | // Doesn't exist, try alternate spelling | ||
| 735 | readStartupCommandFile(userDir, ".jdbrc", canonPath); | ||
| 736 | } | ||
| 737 | } | ||
| 738 | |||
| 739 | // Process interactive commands. | ||
| 740 | MessageOutput.printPrompt(); | ||
| 741 | while (true) { | ||
| 742 | String ln = in.readLine(); | ||
| 743 | if (ln == null) { | ||
| 744 | MessageOutput.println("Input stream closed."); | ||
| 745 | ln = "quit"; | ||
| 746 | } | ||
| 747 | |||
| 748 | if (ln.startsWith("!!") && lastLine != null) { | ||
| 749 | ln = lastLine + ln.substring(2); | ||
| 750 | MessageOutput.printDirectln(ln);// Special case: use printDirectln() | ||
| 751 | } | ||
| 752 | |||
| 753 | StringTokenizer t = new StringTokenizer(ln); | ||
| 754 | if (t.hasMoreTokens()) { | ||
| 755 | lastLine = ln; | ||
| 756 | executeCommand(t); | ||
| 757 | } else { | ||
| 758 | MessageOutput.printPrompt(); | ||
| 759 | } | ||
| 760 | } | ||
| 761 | } catch (VMDisconnectedException e) { | ||
| 762 | handler.handleDisconnectedException(); | ||
| 763 | } | ||
| 764 | } | ||
| 765 | |||
| 766 | private static void usage() { | ||
| 767 | MessageOutput.println("zz usage text", new Object [] {progname, | ||
| 768 | File.pathSeparator}); | ||
| 769 | System.exit(1); | ||
| 770 | } | ||
| 771 | |||
| 772 | static void usageError(String messageKey) { | ||
| 773 | MessageOutput.println(messageKey); | ||
| 774 | MessageOutput.println(); | ||
| 775 | usage(); | ||
| 776 | } | ||
| 777 | |||
| 778 | static void usageError(String messageKey, String argument) { | ||
| 779 | MessageOutput.println(messageKey, argument); | ||
| 780 | MessageOutput.println(); | ||
| 781 | usage(); | ||
| 782 | } | ||
| 783 | |||
| 784 | private static boolean supportsSharedMemory() { | ||
| 785 | for (Connector connector : | ||
| 786 | Bootstrap.virtualMachineManager().allConnectors()) { | ||
| 787 | if (connector.transport() == null) { | ||
| 788 | continue; | ||
| 789 | } | ||
| 790 | if ("dt_shmem".equals(connector.transport().name())) { | ||
| 791 | return true; | ||
| 792 | } | ||
| 793 | } | ||
| 794 | return false; | ||
| 795 | } | ||
| 796 | |||
| 797 | private static String addressToSocketArgs(String address) { | ||
| 798 | int index = address.indexOf(':'); | ||
| 799 | if (index != -1) { | ||
| 800 | String hostString = address.substring(0, index); | ||
| 801 | String portString = address.substring(index + 1); | ||
| 802 | return "hostname=" + hostString + ",port=" + portString; | ||
| 803 | } else { | ||
| 804 | return "port=" + address; | ||
| 805 | } | ||
| 806 | } | ||
| 807 | |||
| 808 | private static boolean hasWhitespace(String string) { | ||
| 809 | int length = string.length(); | ||
| 810 | for (int i = 0; i < length; i++) { | ||
| 811 | if (Character.isWhitespace(string.charAt(i))) { | ||
| 812 | return true; | ||
| 813 | } | ||
| 814 | } | ||
| 815 | return false; | ||
| 816 | } | ||
| 817 | |||
| 818 | private static String addArgument(String string, String argument) { | ||
| 819 | if (hasWhitespace(argument) || argument.indexOf(',') != -1) { | ||
| 820 | // Quotes were stripped out for this argument, add 'em back. | ||
| 821 | StringBuffer buffer = new StringBuffer(string); | ||
| 822 | buffer.append('"'); | ||
| 823 | for (int i = 0; i < argument.length(); i++) { | ||
| 824 | char c = argument.charAt(i); | ||
| 825 | if (c == '"') { | ||
| 826 | buffer.append('\\'); | ||
| 827 | } | ||
| 828 | buffer.append(c); | ||
| 829 | } | ||
| 830 | buffer.append("\" "); | ||
| 831 | return buffer.toString(); | ||
| 832 | } else { | ||
| 833 | return string + argument + ' '; | ||
| 834 | } | ||
| 835 | } | ||
| 836 | |||
| 837 | public static void main(String argv[]) throws MissingResourceException { | ||
| 838 | String cmdLine = ""; | ||
| 839 | String javaArgs = ""; | ||
| 840 | int traceFlags = VirtualMachine.TRACE_NONE; | ||
| 841 | boolean launchImmediately = false; | ||
| 842 | String connectSpec = null; | ||
| 843 | |||
| 844 | MessageOutput.textResources = ResourceBundle.getBundle | ||
| 845 | ("com.sun.tools.example.debug.tty.TTYResources", | ||
| 846 | Locale.getDefault()); | ||
| 847 | |||
| 848 | for (int i = 0; i < argv.length; i++) { | ||
| 849 | String token = argv[i]; | ||
| 850 | if (token.equals("-dbgtrace")) { | ||
| 851 | if ((i == argv.length - 1) || | ||
| 852 | ! Character.isDigit(argv[i+1].charAt(0))) { | ||
| 853 | traceFlags = VirtualMachine.TRACE_ALL; | ||
| 854 | } else { | ||
| 855 | String flagStr = ""; | ||
| 856 | try { | ||
| 857 | flagStr = argv[++i]; | ||
| 858 | traceFlags = Integer.decode(flagStr).intValue(); | ||
| 859 | } catch (NumberFormatException nfe) { | ||
| 860 | usageError("dbgtrace flag value must be an integer:", | ||
| 861 | flagStr); | ||
| 862 | return; | ||
| 863 | } | ||
| 864 | } | ||
| 865 | } else if (token.equals("-X")) { | ||
| 866 | usageError("Use java minus X to see"); | ||
| 867 | return; | ||
| 868 | } else if ( | ||
| 869 | // Standard VM options passed on | ||
| 870 | token.equals("-v") || token.startsWith("-v:") || // -v[:...] | ||
| 871 | token.startsWith("-verbose") || // -verbose[:...] | ||
| 872 | token.startsWith("-D") || | ||
| 873 | // -classpath handled below | ||
| 874 | // NonStandard options passed on | ||
| 875 | token.startsWith("-X") || | ||
| 876 | // Old-style options (These should remain in place as long as | ||
| 877 | // the standard VM accepts them) | ||
| 878 | token.equals("-noasyncgc") || token.equals("-prof") || | ||
| 879 | token.equals("-verify") || token.equals("-noverify") || | ||
| 880 | token.equals("-verifyremote") || | ||
| 881 | token.equals("-verbosegc") || | ||
| 882 | token.startsWith("-ms") || token.startsWith("-mx") || | ||
| 883 | token.startsWith("-ss") || token.startsWith("-oss") ) { | ||
| 884 | |||
| 885 | javaArgs = addArgument(javaArgs, token); | ||
| 886 | } else if (token.equals("-tclassic")) { | ||
| 887 | usageError("Classic VM no longer supported."); | ||
| 888 | return; | ||
| 889 | } else if (token.equals("-tclient")) { | ||
| 890 | // -client must be the first one | ||
| 891 | javaArgs = "-client " + javaArgs; | ||
| 892 | } else if (token.equals("-tserver")) { | ||
| 893 | // -server must be the first one | ||
| 894 | javaArgs = "-server " + javaArgs; | ||
| 895 | } else if (token.equals("-sourcepath")) { | ||
| 896 | if (i == (argv.length - 1)) { | ||
| 897 | usageError("No sourcepath specified."); | ||
| 898 | return; | ||
| 899 | } | ||
| 900 | Env.setSourcePath(argv[++i]); | ||
| 901 | } else if (token.equals("-classpath")) { | ||
| 902 | if (i == (argv.length - 1)) { | ||
| 903 | usageError("No classpath specified."); | ||
| 904 | return; | ||
| 905 | } | ||
| 906 | javaArgs = addArgument(javaArgs, token); | ||
| 907 | javaArgs = addArgument(javaArgs, argv[++i]); | ||
| 908 | } else if (token.equals("-attach")) { | ||
| 909 | if (connectSpec != null) { | ||
| 910 | usageError("cannot redefine existing connection", token); | ||
| 911 | return; | ||
| 912 | } | ||
| 913 | if (i == (argv.length - 1)) { | ||
| 914 | usageError("No attach address specified."); | ||
| 915 | return; | ||
| 916 | } | ||
| 917 | String address = argv[++i]; | ||
| 918 | |||
| 919 | /* | ||
| 920 | * -attach is shorthand for one of the reference implementation's | ||
| 921 | * attaching connectors. Use the shared memory attach if it's | ||
| 922 | * available; otherwise, use sockets. Build a connect | ||
| 923 | * specification string based on this decision. | ||
| 924 | */ | ||
| 925 | if (supportsSharedMemory()) { | ||
| 926 | connectSpec = "com.sun.jdi.SharedMemoryAttach:name=" + | ||
| 927 | address; | ||
| 928 | } else { | ||
| 929 | String suboptions = addressToSocketArgs(address); | ||
| 930 | connectSpec = "com.sun.jdi.SocketAttach:" + suboptions; | ||
| 931 | } | ||
| 932 | } else if (token.equals("-listen") || token.equals("-listenany")) { | ||
| 933 | if (connectSpec != null) { | ||
| 934 | usageError("cannot redefine existing connection", token); | ||
| 935 | return; | ||
| 936 | } | ||
| 937 | String address = null; | ||
| 938 | if (token.equals("-listen")) { | ||
| 939 | if (i == (argv.length - 1)) { | ||
| 940 | usageError("No attach address specified."); | ||
| 941 | return; | ||
| 942 | } | ||
| 943 | address = argv[++i]; | ||
| 944 | } | ||
| 945 | |||
| 946 | /* | ||
| 947 | * -listen[any] is shorthand for one of the reference implementation's | ||
| 948 | * listening connectors. Use the shared memory listen if it's | ||
| 949 | * available; otherwise, use sockets. Build a connect | ||
| 950 | * specification string based on this decision. | ||
| 951 | */ | ||
| 952 | if (supportsSharedMemory()) { | ||
| 953 | connectSpec = "com.sun.jdi.SharedMemoryListen:"; | ||
| 954 | if (address != null) { | ||
| 955 | connectSpec += ("name=" + address); | ||
| 956 | } | ||
| 957 | } else { | ||
| 958 | connectSpec = "com.sun.jdi.SocketListen:"; | ||
| 959 | if (address != null) { | ||
| 960 | connectSpec += addressToSocketArgs(address); | ||
| 961 | } | ||
| 962 | } | ||
| 963 | } else if (token.equals("-launch")) { | ||
| 964 | launchImmediately = true; | ||
| 965 | } else if (token.equals("-listconnectors")) { | ||
| 966 | Commands evaluator = new Commands(); | ||
| 967 | evaluator.commandConnectors(Bootstrap.virtualMachineManager()); | ||
| 968 | return; | ||
| 969 | } else if (token.equals("-connect")) { | ||
| 970 | /* | ||
| 971 | * -connect allows the user to pick the connector | ||
| 972 | * used in bringing up the target VM. This allows | ||
| 973 | * use of connectors other than those in the reference | ||
| 974 | * implementation. | ||
| 975 | */ | ||
| 976 | if (connectSpec != null) { | ||
| 977 | usageError("cannot redefine existing connection", token); | ||
| 978 | return; | ||
| 979 | } | ||
| 980 | if (i == (argv.length - 1)) { | ||
| 981 | usageError("No connect specification."); | ||
| 982 | return; | ||
| 983 | } | ||
| 984 | connectSpec = argv[++i]; | ||
| 985 | } else if (token.equals("-help")) { | ||
| 986 | usage(); | ||
| 987 | } else if (token.equals("-version")) { | ||
| 988 | Commands evaluator = new Commands(); | ||
| 989 | evaluator.commandVersion(progname, | ||
| 990 | Bootstrap.virtualMachineManager()); | ||
| 991 | System.exit(0); | ||
| 992 | } else if (token.startsWith("-")) { | ||
| 993 | usageError("invalid option", token); | ||
| 994 | return; | ||
| 995 | } else { | ||
| 996 | // Everything from here is part of the command line | ||
| 997 | cmdLine = addArgument("", token); | ||
| 998 | for (i++; i < argv.length; i++) { | ||
| 999 | cmdLine = addArgument(cmdLine, argv[i]); | ||
| 1000 | } | ||
| 1001 | break; | ||
| 1002 | } | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | /* | ||
| 1006 | * Unless otherwise specified, set the default connect spec. | ||
| 1007 | */ | ||
| 1008 | |||
| 1009 | /* | ||
| 1010 | * Here are examples of jdb command lines and how the options | ||
| 1011 | * are interpreted as arguments to the program being debugged. | ||
| 1012 | * arg1 arg2 | ||
| 1013 | * ---- ---- | ||
| 1014 | * jdb hello a b a b | ||
| 1015 | * jdb hello "a b" a b | ||
| 1016 | * jdb hello a,b a,b | ||
| 1017 | * jdb hello a, b a, b | ||
| 1018 | * jdb hello "a, b" a, b | ||
| 1019 | * jdb -connect "com.sun.jdi.CommandLineLaunch:main=hello a,b" illegal | ||
| 1020 | * jdb -connect com.sun.jdi.CommandLineLaunch:main=hello "a,b" illegal | ||
| 1021 | * jdb -connect 'com.sun.jdi.CommandLineLaunch:main=hello "a,b"' arg1 = a,b | ||
| 1022 | * jdb -connect 'com.sun.jdi.CommandLineLaunch:main=hello "a b"' arg1 = a b | ||
| 1023 | * jdb -connect 'com.sun.jdi.CommandLineLaunch:main=hello a b' arg1 = a arg2 = b | ||
| 1024 | * jdb -connect 'com.sun.jdi.CommandLineLaunch:main=hello "a," b' arg1 = a, arg2 = b | ||
| 1025 | */ | ||
| 1026 | if (connectSpec == null) { | ||
| 1027 | connectSpec = "com.sun.jdi.CommandLineLaunch:"; | ||
| 1028 | } else if (!connectSpec.endsWith(",") && !connectSpec.endsWith(":")) { | ||
| 1029 | connectSpec += ","; // (Bug ID 4285874) | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | cmdLine = cmdLine.trim(); | ||
| 1033 | javaArgs = javaArgs.trim(); | ||
| 1034 | |||
| 1035 | if (cmdLine.length() > 0) { | ||
| 1036 | if (!connectSpec.startsWith("com.sun.jdi.CommandLineLaunch:")) { | ||
| 1037 | usageError("Cannot specify command line with connector:", | ||
| 1038 | connectSpec); | ||
| 1039 | return; | ||
| 1040 | } | ||
| 1041 | connectSpec += "main=" + cmdLine + ","; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | if (javaArgs.length() > 0) { | ||
| 1045 | if (!connectSpec.startsWith("com.sun.jdi.CommandLineLaunch:")) { | ||
| 1046 | usageError("Cannot specify target vm arguments with connector:", | ||
| 1047 | connectSpec); | ||
| 1048 | return; | ||
| 1049 | } | ||
| 1050 | connectSpec += "options=" + javaArgs + ","; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | try { | ||
| 1054 | if (! connectSpec.endsWith(",")) { | ||
| 1055 | connectSpec += ","; // (Bug ID 4285874) | ||
| 1056 | } | ||
| 1057 | Env.init(connectSpec, launchImmediately, traceFlags); | ||
| 1058 | new TTY(); | ||
| 1059 | } catch(Exception e) { | ||
| 1060 | MessageOutput.printException("Internal exception:", e); | ||
| 1061 | } | ||
| 1062 | } | ||
| 1063 | } | ||