1 /******************************************************************************* 2 * Copyright (c) 2005, 2018 Wind River Systems and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * Bjorn Freeman-Benson - initial API and implementation 13 * Pawel Piech (Wind River) - ported PDA Virtual Machine to Java (Bug 261400) 14 * IBM Coporation - bug fixing 15 *******************************************************************************/ 16 package org.eclipse.debug.examples.pdavm; 17 18 import java.io.BufferedReader; 19 import java.io.FileReader; 20 import java.io.IOException; 21 import java.io.InputStreamReader; 22 import java.io.OutputStream; 23 import java.io.PrintStream; 24 import java.io.StringWriter; 25 import java.net.ServerSocket; 26 import java.net.Socket; 27 import java.util.ArrayList; 28 import java.util.HashMap; 29 import java.util.Iterator; 30 import java.util.LinkedHashMap; 31 import java.util.LinkedList; 32 import java.util.List; 33 import java.util.Map; 34 import java.util.Map.Entry; 35 import java.util.StringTokenizer; 36 import java.util.TreeSet; 37 import java.util.regex.Matcher; 38 import java.util.regex.Pattern; 39 40 /** 41 * Push Down Automata interpreter. 42 * 43 * @since 3.5 44 */ 45 public class PDAVirtualMachine { 46 47 static class Stack extends LinkedList<Object> { 48 private static final long serialVersionUID = 1L; 49 50 @Override pop()51 public Object pop() { 52 return isEmpty() ? Integer.valueOf(0) : remove(size() - 1); 53 } 54 55 @Override push(Object value)56 public void push(Object value) { 57 add(value); 58 } 59 } 60 61 static class Register { Register(String name)62 Register(String name) { 63 fName = name; 64 } 65 String fName; 66 String fGroup = "<no_group>"; //$NON-NLS-1$ 67 boolean fIsWriteable = true; 68 Map<String, BitField> fBitFields = new LinkedHashMap<>(0); 69 int fValue; 70 } 71 72 static class BitField { BitField(String name)73 BitField(String name) { 74 fName = name; 75 } 76 String fName; 77 int fBitOffset; 78 int fBitCount; 79 Map<String, Integer> fMnemonics = new LinkedHashMap<>(0); 80 } 81 82 Map<String, Register> fRegisters = new LinkedHashMap<>(0); 83 84 class Args { 85 final String[] fArgs; 86 87 int next = 0; 88 Args(String[] args)89 Args(String[] args) { 90 fArgs = args; 91 } 92 hasNextArg()93 boolean hasNextArg() { 94 return fArgs.length > next; 95 } 96 getNextStringArg()97 String getNextStringArg() { 98 if (fArgs.length > next) { 99 return fArgs[next++]; 100 } 101 return ""; //$NON-NLS-1$ 102 } 103 getNextIntArg()104 int getNextIntArg() { 105 String arg = getNextStringArg(); 106 try { 107 return Integer.parseInt(arg); 108 } catch (NumberFormatException e) { 109 } 110 return 0; 111 } 112 getNextBooleanArg()113 boolean getNextBooleanArg() { 114 String arg = getNextStringArg(); 115 try { 116 return Boolean.getBoolean(arg); 117 } catch (NumberFormatException e) { 118 } 119 return false; 120 } 121 getNextIntOrStringArg()122 Object getNextIntOrStringArg() { 123 String arg = getNextStringArg(); 124 try { 125 return Integer.valueOf(arg); 126 } catch (NumberFormatException e) { 127 } 128 return arg; 129 } 130 getThreadArg()131 PDAThread getThreadArg() { 132 int id = getNextIntArg(); 133 return fThreads.get( Integer.valueOf(id) ); 134 } 135 } 136 137 class PDAThread { 138 final int fID; 139 140 /** The push down automata data stack (the data stack). */ 141 final Stack fStack = new Stack(); 142 143 /** 144 * PDAThread copy of the code. It can differ from the program if 145 * performing an evaluation. 146 */ 147 String[] fThreadCode; 148 149 /** PDAThread copy of the labels. */ 150 Map<String, Integer> fThreadLabels; 151 152 /** The stack of stack frames (the control stack) */ 153 final List<Frame> fFrames = new LinkedList<>(); 154 155 /** Current stack frame (not includced in fFrames) */ 156 Frame fCurrentFrame; 157 158 /** 159 * The run flag is true if the thread is running. If the run flag is 160 * false, the thread exits the next time the main instruction loop runs. 161 */ 162 boolean fRun = true; 163 164 String fSuspend = null; 165 166 boolean fStep = false; 167 168 boolean fStepReturn = false; 169 170 int fSavedPC; 171 172 boolean fPerformingEval = false; 173 PDAThread(int id, String function, int pc)174 PDAThread(int id, String function, int pc) { 175 fID = id; 176 fCurrentFrame = new Frame(function, pc); 177 fThreadCode = fCode; 178 fThreadLabels = fLabels; 179 } 180 } 181 182 final Map<Integer, PDAThread> fThreads = new LinkedHashMap<>(); 183 184 int fNextThreadId = 1; 185 186 boolean fStarted = true; 187 /** 188 * The code is stored as an array of strings, each line of the source file 189 * being one entry in the array. 190 */ 191 final String[] fCode; 192 193 /** A mapping of labels to indicies in the code array */ 194 final Map<String, Integer> fLabels; 195 196 /** Each stack frame is a mapping of variable names to values. */ 197 class Frame { 198 final Map<String, Object> fLocalVariables = new LinkedHashMap<>(); 199 200 /** 201 * The name of the function in this frame 202 */ 203 final String fFunction; 204 205 /** 206 * The current program counter in the frame the pc points to the next 207 * instruction to be executed 208 */ 209 int fPC; 210 Frame(String function, int pc)211 Frame(String function, int pc) { 212 fFunction = function; 213 fPC = pc; 214 } 215 set(String name, Object value)216 void set(String name, Object value) { 217 if (name.startsWith("$")) { //$NON-NLS-1$ 218 setRegisterValue(name, value); 219 } else { 220 fLocalVariables.put(name, value); 221 } 222 } 223 get(String name)224 Object get(String name) { 225 if (name.startsWith("$")) { //$NON-NLS-1$ 226 return getRegisterValue(name); 227 } else { 228 return fLocalVariables.get(name); 229 } 230 } 231 } 232 setRegisterValue(String name, Object value)233 void setRegisterValue(String name, Object value) { 234 Register reg = fRegisters.get(getRegisterPartOfName(name)); 235 if (reg == null) { 236 return; 237 } 238 String bitFieldName = getBitFieldPartOfName(name); 239 if (bitFieldName != null) { 240 BitField bitField = reg.fBitFields.get(bitFieldName); 241 if (bitField == null) { 242 return; 243 } 244 Integer intValue = null; 245 if (value instanceof Integer) { 246 intValue = (Integer)value; 247 } else if (value instanceof String) { 248 intValue = bitField.fMnemonics.get(value); 249 } 250 if (intValue != null) { 251 int bitFieldMask = 2^(bitField.fBitCount - 1); 252 int registerMask = ~(bitFieldMask << bitField.fBitOffset); 253 int bitFieldValue = intValue.intValue() & bitFieldMask; 254 reg.fValue = (reg.fValue & registerMask) | (bitFieldValue << bitField.fBitOffset); 255 } 256 } else if (value instanceof Integer) { 257 reg.fValue = ((Integer)value).intValue(); 258 } 259 } 260 getRegisterValue(String name)261 Object getRegisterValue(String name) { 262 Register reg = fRegisters.get(getRegisterPartOfName(name)); 263 if (reg == null) { 264 return null; 265 } 266 String bitFieldName = getBitFieldPartOfName(name); 267 if (bitFieldName != null) { 268 BitField bitField = reg.fBitFields.get(bitFieldName); 269 if (bitField == null) { 270 return null; 271 } 272 int bitFieldMask = 2^(bitField.fBitCount - 1); 273 int registerMask = bitFieldMask << bitField.fBitOffset; 274 return Integer.valueOf( (reg.fValue & registerMask) >> bitField.fBitOffset ); 275 } else { 276 return Integer.valueOf(reg.fValue); 277 } 278 } 279 280 /** 281 * Breakpoints are stored per each each line of code. The boolean indicates 282 * whether the whole VM should suspend or just the triggering thread. 283 */ 284 final Map<Integer, Boolean> fBreakpoints = new HashMap<>(); 285 286 /** 287 * The suspend flag is true if the VM should suspend running the program and 288 * just listen for debug commands. 289 */ 290 String fSuspendVM; 291 292 /** Flag indicating whether the debugger is performing a step. */ 293 boolean fStepVM = false; 294 295 /** Flag indicating whether the debugger is performing a step return */ 296 boolean fStepReturnVM = false; 297 298 int fSteppingThread = 0; 299 300 /** Name of the pda program being debugged */ 301 final String fFilename; 302 303 /** The command line argument to start a debug session. */ 304 final boolean fDebug; 305 306 /** The port to listen for debug commands on */ 307 final int fCommandPort; 308 309 /** 310 * Command socket for receiving debug commands and sending command responses 311 */ 312 Socket fCommandSocket; 313 314 /** Command socket reader */ 315 BufferedReader fCommandReceiveStream; 316 317 /** Command socket write stream. */ 318 OutputStream fCommandResponseStream; 319 320 /** The port to send debug events to */ 321 final int fEventPort; 322 323 /** Event socket */ 324 Socket fEventSocket; 325 326 /** Event socket and write stream. */ 327 OutputStream fEventStream; 328 329 /** The eventstops table holds which events cause suspends and which do not. */ 330 final Map<String, Boolean> fEventStops = new HashMap<>(); 331 { 332 fEventStops.put("unimpinstr", Boolean.FALSE); //$NON-NLS-1$ 333 fEventStops.put("nosuchlabel", Boolean.FALSE); //$NON-NLS-1$ 334 } 335 336 /** 337 * The watchpoints table holds watchpoint information. 338 * <p/> 339 * variablename_stackframedepth => N 340 * <ul> 341 * <li>N = 0 is no watch</li> 342 * <li>N = 1 is read watch</li> 343 * <li>N = 2 is write watch</li> 344 * <li>N = 3 is both, etc.</li> 345 */ 346 final Map<String, Integer> fWatchpoints = new HashMap<>(); 347 main(String[] args)348 public static void main(String[] args) { 349 String programFile = args.length >= 1 ? args[0] : null; 350 if (programFile == null) { 351 System.err.println("Error: No program specified"); //$NON-NLS-1$ 352 return; 353 } 354 355 String debugFlag = args.length >= 2 ? args[1] : ""; //$NON-NLS-1$ 356 boolean debug = "-debug".equals(debugFlag); //$NON-NLS-1$ 357 int commandPort = 0; 358 int eventPort = 0; 359 360 if (debug) { 361 String commandPortStr = args.length >= 3 ? args[2] : ""; //$NON-NLS-1$ 362 try { 363 commandPort = Integer.parseInt(commandPortStr); 364 } catch (NumberFormatException e) { 365 System.err.println("Error: Invalid command port"); //$NON-NLS-1$ 366 return; 367 } 368 369 String eventPortStr = args.length >= 4 ? args[3] : ""; //$NON-NLS-1$ 370 try { 371 eventPort = Integer.parseInt(eventPortStr); 372 } catch (NumberFormatException e) { 373 System.err.println("Error: Invalid event port"); //$NON-NLS-1$ 374 return; 375 } 376 } 377 378 PDAVirtualMachine pdaVM = null; 379 try { 380 pdaVM = new PDAVirtualMachine(programFile, debug, commandPort, eventPort); 381 pdaVM.startDebugger(); 382 } catch (IOException e) { 383 System.err.println("Error: " + e); //$NON-NLS-1$ 384 return; 385 } 386 pdaVM.run(); 387 } 388 PDAVirtualMachine(String inputFile, boolean debug, int commandPort, int eventPort)389 PDAVirtualMachine(String inputFile, boolean debug, int commandPort, int eventPort) throws IOException { 390 fFilename = inputFile; 391 392 // Load all the code into memory 393 StringWriter stringWriter = new StringWriter(); 394 List<String> code = new LinkedList<>(); 395 try (FileReader fileReader = new FileReader(inputFile)) { 396 int c = fileReader.read(); 397 while (c != -1) { 398 if (c == '\n') { 399 code.add(stringWriter.toString().trim()); 400 stringWriter = new StringWriter(); 401 } else { 402 stringWriter.write(c); 403 } 404 c = fileReader.read(); 405 } 406 } 407 408 code.add(stringWriter.toString().trim()); 409 fCode = code.toArray(new String[code.size()]); 410 411 fLabels = mapLabels(fCode); 412 413 fDebug = debug; 414 fCommandPort = commandPort; 415 fEventPort = eventPort; 416 } 417 418 /** 419 * Initializes the labels map 420 */ mapLabels(String[] code)421 Map<String, Integer> mapLabels(String[] code) { 422 Map<String, Integer> labels = new HashMap<>(); 423 for (int i = 0; i < code.length; i++) { 424 if (code[i].length() != 0 && code[i].charAt(0) == ':') { 425 labels.put(code[i].substring(1), Integer.valueOf(i)); 426 } 427 } 428 return labels; 429 } 430 sendCommandResponse(String response)431 void sendCommandResponse(String response) { 432 try { 433 fCommandResponseStream.write(response.getBytes()); 434 fCommandResponseStream.flush(); 435 } catch (IOException e) { 436 } 437 } 438 sendDebugEvent(String event, boolean error)439 void sendDebugEvent(String event, boolean error) { 440 if (fDebug) { 441 try { 442 fEventStream.write(event.getBytes()); 443 fEventStream.write('\n'); 444 fEventStream.flush(); 445 } catch (IOException e) { 446 System.err.println("Error: " + e); //$NON-NLS-1$ 447 System.exit(1); 448 } 449 } else if (error) { 450 System.err.println("Error: " + event); //$NON-NLS-1$ 451 } 452 } 453 startDebugger()454 void startDebugger() throws IOException { 455 if (fDebug) { 456 System.out.println("-debug " + fCommandPort + " " + fEventPort); //$NON-NLS-1$ //$NON-NLS-2$ 457 } 458 459 try (ServerSocket commandServerSocket = new ServerSocket(fCommandPort)) { 460 fCommandSocket = commandServerSocket.accept(); 461 fCommandReceiveStream = new BufferedReader(new InputStreamReader(fCommandSocket.getInputStream())); 462 fCommandResponseStream = new PrintStream(fCommandSocket.getOutputStream()); 463 } 464 465 try (ServerSocket eventServerSocket = new ServerSocket(fEventPort)) { 466 fEventSocket = eventServerSocket.accept(); 467 fEventStream = new PrintStream(fEventSocket.getOutputStream()); 468 } 469 470 System.out.println("debug connection accepted"); //$NON-NLS-1$ 471 472 fSuspendVM = "client"; //$NON-NLS-1$ 473 } 474 run()475 void run() { 476 int id = fNextThreadId++; 477 sendDebugEvent("vmstarted", false); //$NON-NLS-1$ 478 fThreads.put(Integer.valueOf(id), new PDAThread(id, "main", 0)); //$NON-NLS-1$ 479 if (fDebug) { 480 sendDebugEvent("started " + id, false); //$NON-NLS-1$ 481 } 482 483 boolean allThreadsSuspended = false; 484 while (!fThreads.isEmpty()) { 485 checkForBreakpoint(); 486 487 if (fSuspendVM != null) { 488 debugUI(); 489 } else { 490 yieldToDebug(allThreadsSuspended); 491 if (fSuspendVM != null) { 492 // Received a command to suspend VM, skip executing threads. 493 continue; 494 } 495 } 496 497 PDAThread[] threadsCopy = fThreads.values().toArray(new PDAThread[fThreads.size()]); 498 allThreadsSuspended = true; 499 for (int i = 0; i < threadsCopy.length; i++) { 500 PDAThread thread = threadsCopy[i]; 501 if (thread.fSuspend == null) { 502 allThreadsSuspended = false; 503 504 String instruction = thread.fThreadCode[thread.fCurrentFrame.fPC]; 505 thread.fCurrentFrame.fPC++; 506 doOneInstruction(thread, instruction); 507 if (thread.fCurrentFrame.fPC >= thread.fThreadCode.length) { 508 // Thread reached end of code, exit from the thread. 509 thread.fRun = false; 510 } else if (thread.fStepReturn) { 511 // If this thread is in a step-return operation, check 512 // if we've returned from a call. 513 instruction = thread.fThreadCode[thread.fCurrentFrame.fPC]; 514 if ("return".equals(instruction)) { //$NON-NLS-1$ 515 // Note: this will only be triggered if the current 516 // thread also has the fStepReturn flag set. 517 if (fStepReturnVM) { 518 fSuspendVM = thread.fID + " step"; //$NON-NLS-1$ 519 } else { 520 thread.fSuspend = "step"; //$NON-NLS-1$ 521 } 522 } 523 } 524 if (!thread.fRun) { 525 sendDebugEvent("exited " + thread.fID, false); //$NON-NLS-1$ 526 fThreads.remove(Integer.valueOf(thread.fID)); 527 } else if (thread.fSuspend != null) { 528 sendDebugEvent("suspended " + thread.fID + " " + thread.fSuspend, false); //$NON-NLS-1$ //$NON-NLS-2$ 529 thread.fStep = thread.fStepReturn = thread.fPerformingEval = false; 530 } 531 } 532 } 533 534 // Force thread context switch to avoid starving out other 535 // processes in the system. 536 Thread.yield(); 537 } 538 539 sendDebugEvent("vmterminated", false); //$NON-NLS-1$ 540 if (fDebug) { 541 try { 542 fCommandReceiveStream.close(); 543 fCommandResponseStream.close(); 544 fCommandSocket.close(); 545 fEventStream.close(); 546 fEventSocket.close(); 547 } catch (IOException e) { 548 System.out.println("Error: " + e); //$NON-NLS-1$ 549 } 550 } 551 552 } 553 doOneInstruction(PDAThread thread, String instr)554 void doOneInstruction(PDAThread thread, String instr) { 555 StringTokenizer tokenizer = new StringTokenizer(instr); 556 String op = tokenizer.nextToken(); 557 List<String> tokens = new LinkedList<>(); 558 while (tokenizer.hasMoreTokens()) { 559 tokens.add(tokenizer.nextToken()); 560 } 561 Args args = new Args( tokens.toArray(new String[tokens.size()]) ); 562 563 boolean opValid = true; 564 if (op.equals("add")) { //$NON-NLS-1$ 565 iAdd(thread, args); 566 } else if (op.equals("branch_not_zero")) { //$NON-NLS-1$ 567 iBranchNotZero(thread, args); 568 } else if (op.equals("call")) { //$NON-NLS-1$ 569 iCall(thread, args); 570 } else if (op.equals("dec")) { //$NON-NLS-1$ 571 iDec(thread, args); 572 } else if (op.equals("def")) { //$NON-NLS-1$ 573 iDef(thread, args); 574 } else if (op.equals("dup")) { //$NON-NLS-1$ 575 iDup(thread, args); 576 } else if (op.equals("exec")) { //$NON-NLS-1$ 577 iExec(thread, args); 578 } else if (op.equals("halt")) { //$NON-NLS-1$ 579 iHalt(thread, args); 580 } else if (op.equals("output")) { //$NON-NLS-1$ 581 iOutput(thread, args); 582 } else if (op.equals("pop")) { //$NON-NLS-1$ 583 iPop(thread, args); 584 } else if (op.equals("push")) { //$NON-NLS-1$ 585 iPush(thread, args); 586 } else if (op.equals("return")) { //$NON-NLS-1$ 587 iReturn(thread, args); 588 } else if (op.equals("var")) { //$NON-NLS-1$ 589 iVar(thread, args); 590 } else if (op.equals("xyzzy")) { //$NON-NLS-1$ 591 iInternalEndEval(thread, args); 592 } else if (op.startsWith(":")) {} // label //$NON-NLS-1$ 593 else if (op.startsWith("#")) {} // comment //$NON-NLS-1$ 594 else { 595 opValid = false; 596 } 597 598 if (!opValid) { 599 sendDebugEvent("unimplemented instruction " + op, true); //$NON-NLS-1$ 600 if ( fEventStops.get("unimpinstr").booleanValue() ) { //$NON-NLS-1$ 601 fSuspendVM = thread.fID + " event unimpinstr"; //$NON-NLS-1$ 602 thread.fCurrentFrame.fPC--; 603 } 604 } else if (thread.fStep) { 605 if (fStepVM) { 606 fSuspendVM = thread.fID + " step"; //$NON-NLS-1$ 607 fStepVM = false; 608 } else { 609 thread.fSuspend = "step"; //$NON-NLS-1$ 610 } 611 thread.fStep = false; 612 } 613 } 614 checkForBreakpoint()615 void checkForBreakpoint() { 616 if (fDebug) { 617 for (Iterator<PDAThread> itr = fThreads.values().iterator(); itr.hasNext();) { 618 PDAThread thread = itr.next(); 619 Integer pc = Integer.valueOf(thread.fCurrentFrame.fPC); 620 // Suspend for breakpoint if: 621 // - the VM is not yet set to suspend, for e.g. as a result of step end, 622 // - the thread is not yet suspended and is not performing an evaluation 623 // - the breakpoints table contains a breakpoint for the given line. 624 if (fSuspendVM == null && 625 thread.fSuspend == null && !thread.fPerformingEval && 626 fBreakpoints.containsKey(pc)) 627 { 628 if ( fBreakpoints.get(pc).booleanValue() ) { 629 fSuspendVM = thread.fID + " breakpoint " + pc; //$NON-NLS-1$ 630 } else { 631 thread.fSuspend = "breakpoint " + pc; //$NON-NLS-1$ 632 thread.fStep = thread.fStepReturn = false; 633 sendDebugEvent("suspended " + thread.fID + " " + thread.fSuspend, false); //$NON-NLS-1$ //$NON-NLS-2$ 634 } 635 } 636 } 637 } 638 } 639 640 /** 641 * After each instruction, we check the debug command channel for control input. If 642 * there are commands, process them. 643 */ yieldToDebug(boolean allThreadsSuspended)644 void yieldToDebug(boolean allThreadsSuspended) { 645 if (fDebug) { 646 String line = ""; //$NON-NLS-1$ 647 try { 648 if (allThreadsSuspended || fCommandReceiveStream.ready()) { 649 line = fCommandReceiveStream.readLine(); 650 processDebugCommand(line); 651 } 652 } catch (IOException e) { 653 System.err.println("Error: " + e); //$NON-NLS-1$ 654 System.exit(1); 655 } 656 } 657 } 658 659 /** 660 * Service the debugger commands while the VM is suspended 661 */ debugUI()662 void debugUI() { 663 if (!fStarted) { 664 sendDebugEvent("vmsuspended " + fSuspendVM, false); //$NON-NLS-1$ 665 } else { 666 fStarted = false; 667 } 668 669 // Clear all stepping flags. In case the VM suspended while 670 // a step operation was being performed for the VM or some thread. 671 fStepVM = fStepReturnVM = false; 672 for (Iterator<PDAThread> itr = fThreads.values().iterator(); itr.hasNext();) { 673 PDAThread thread = itr.next(); 674 thread.fSuspend = null; 675 thread.fStep = thread.fStepReturn = thread.fPerformingEval = false; 676 } 677 678 while (fSuspendVM != null) { 679 String line = ""; //$NON-NLS-1$ 680 try { 681 line = fCommandReceiveStream.readLine(); 682 } catch (IOException e) { 683 System.err.println("Error: " + e); //$NON-NLS-1$ 684 System.exit(1); 685 return; 686 } 687 processDebugCommand(line); 688 } 689 690 if (fStepVM || fStepReturnVM) { 691 sendDebugEvent("vmresumed step", false); //$NON-NLS-1$ 692 } else { 693 sendDebugEvent("vmresumed client", false); //$NON-NLS-1$ 694 } 695 } 696 processDebugCommand(String line)697 void processDebugCommand(String line) { 698 StringTokenizer tokenizer = new StringTokenizer(line.trim()); 699 if (line.length() == 0) { 700 return; 701 } 702 703 String command = tokenizer.nextToken(); 704 List<String> tokens = new LinkedList<>(); 705 while (tokenizer.hasMoreTokens()) { 706 tokens.add(tokenizer.nextToken()); 707 } 708 Args args = new Args( tokens.toArray(new String[tokens.size()])); 709 710 if ("children".equals(command)) { //$NON-NLS-1$ 711 debugChildren(args); 712 } else if ("clear".equals(command)) { //$NON-NLS-1$ 713 debugClearBreakpoint(args); 714 } else if ("data".equals(command)) { //$NON-NLS-1$ 715 debugData(args); 716 } else if ("drop".equals(command)) { //$NON-NLS-1$ 717 debugDropFrame(args); 718 } else if ("eval".equals(command)) { //$NON-NLS-1$ 719 debugEval(args); 720 } else if ("eventstop".equals(command)) { //$NON-NLS-1$ 721 debugEventStop(args); 722 } else if ("frame".equals(command)) { //$NON-NLS-1$ 723 debugFrame(args); 724 } else if ("groups".equals(command)) { //$NON-NLS-1$ 725 debugGroups(args); 726 } else if ("popdata".equals(command)) { //$NON-NLS-1$ 727 debugPopData(args); 728 } else if ("pushdata".equals(command)) { //$NON-NLS-1$ 729 debugPushData(args); 730 } else if ("registers".equals(command)) { //$NON-NLS-1$ 731 debugRegisters(args); 732 } else if ("restart".equals(command)) { //$NON-NLS-1$ 733 debugRestart(args); 734 } else if ("resume".equals(command)) { //$NON-NLS-1$ 735 debugResume(args); 736 } else if ("set".equals(command)) { //$NON-NLS-1$ 737 debugSetBreakpoint(args); 738 } else if ("setdata".equals(command)) { //$NON-NLS-1$ 739 debugSetData(args); 740 } else if ("setvar".equals(command)) { //$NON-NLS-1$ 741 debugSetVariable(args); 742 } else if ("stack".equals(command)) { //$NON-NLS-1$ 743 debugStack(args); 744 } else if ("stackdepth".equals(command)) { //$NON-NLS-1$ 745 debugStackDepth(args); 746 } else if ("state".equals(command)) { //$NON-NLS-1$ 747 debugState(args); 748 } else if ("step".equals(command)) { //$NON-NLS-1$ 749 debugStep(args); 750 } else if ("stepreturn".equals(command)) { //$NON-NLS-1$ 751 debugStepReturn(args); 752 } else if ("suspend".equals(command)) { //$NON-NLS-1$ 753 debugSuspend(args); 754 } else if ("terminate".equals(command)) { //$NON-NLS-1$ 755 debugTerminate(); 756 } else if ("threads".equals(command)) { //$NON-NLS-1$ 757 debugThreads(); 758 } else if ("var".equals(command)) { //$NON-NLS-1$ 759 debugVar(args); 760 } else if ("vmresume".equals(command)) { //$NON-NLS-1$ 761 debugVMResume(); 762 } else if ("vmsuspend".equals(command)) { //$NON-NLS-1$ 763 debugVMSuspend(); 764 } else if ("watch".equals(command)) { //$NON-NLS-1$ 765 debugWatch(args); 766 } else { 767 sendCommandResponse("error: invalid command\n"); //$NON-NLS-1$ 768 } 769 } 770 debugChildren(Args args)771 void debugChildren(Args args) { 772 PDAThread thread = args.getThreadArg(); 773 if (thread == null) { 774 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 775 return; 776 } 777 778 int sfnumber = args.getNextIntArg(); 779 String var = args.getNextStringArg(); 780 781 Frame frame = sfnumber >= thread.fFrames.size() 782 ? thread.fCurrentFrame : (Frame)thread.fFrames.get(sfnumber); 783 784 String varDot = var + "."; //$NON-NLS-1$ 785 List<String> children = new ArrayList<>(); 786 for (Iterator<String> itr = frame.fLocalVariables.keySet().iterator(); itr.hasNext();) { 787 String localVar = itr.next(); 788 if (localVar.startsWith(varDot) && localVar.indexOf('.', varDot.length() + 1) == -1) { 789 children.add(localVar); 790 } 791 } 792 793 StringBuilder result = new StringBuilder(); 794 for (Iterator<String> itr = children.iterator(); itr.hasNext();) { 795 result.append(itr.next()); 796 result.append('|'); 797 } 798 result.append('\n'); 799 800 sendCommandResponse(result.toString()); 801 } 802 debugClearBreakpoint(Args args)803 void debugClearBreakpoint(Args args) { 804 int line = args.getNextIntArg(); 805 806 fBreakpoints.remove( Integer.valueOf(line) ); 807 sendCommandResponse("ok\n"); //$NON-NLS-1$ 808 } 809 810 private static Pattern fPackPattern = Pattern.compile("%([a-fA-F0-9][a-fA-F0-9])"); //$NON-NLS-1$ 811 debugData(Args args)812 void debugData(Args args) { 813 PDAThread thread = args.getThreadArg(); 814 if (thread == null) { 815 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 816 return; 817 } 818 819 StringBuilder result = new StringBuilder(); 820 for (Iterator<?> itr = thread.fStack.iterator(); itr.hasNext();) { 821 result.append(itr.next()); 822 result.append('|'); 823 } 824 result.append('\n'); 825 sendCommandResponse(result.toString()); 826 } 827 debugDropFrame(Args args)828 void debugDropFrame(Args args) { 829 PDAThread thread = args.getThreadArg(); 830 if (thread == null) { 831 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 832 return; 833 } 834 835 if (!thread.fFrames.isEmpty()) { 836 thread.fCurrentFrame = thread.fFrames.remove(thread.fFrames.size() - 1); 837 } 838 thread.fCurrentFrame.fPC--; 839 sendCommandResponse("ok\n"); //$NON-NLS-1$ 840 if (fSuspendVM != null) { 841 sendDebugEvent("vmresumed drop", false); //$NON-NLS-1$ 842 sendDebugEvent("vmsuspended " + thread.fID + " drop", false); //$NON-NLS-1$ //$NON-NLS-2$ 843 } else { 844 sendDebugEvent("resumed " + thread.fID + " drop", false); //$NON-NLS-1$ //$NON-NLS-2$ 845 sendDebugEvent("suspended " + thread.fID + " drop", false); //$NON-NLS-1$ //$NON-NLS-2$ 846 } 847 } 848 debugEval(Args args)849 void debugEval(Args args) { 850 if (fSuspendVM != null) { 851 sendCommandResponse("error: cannot evaluate while vm is suspended\n"); //$NON-NLS-1$ 852 return; 853 } 854 855 PDAThread thread = args.getThreadArg(); 856 if (thread == null) { 857 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 858 return; 859 } 860 861 if (thread.fSuspend == null) { 862 sendCommandResponse("error: thread running\n"); //$NON-NLS-1$ 863 return; 864 } 865 866 StringTokenizer tokenizer = new StringTokenizer(args.getNextStringArg(), "|"); //$NON-NLS-1$ 867 tokenizer.countTokens(); 868 869 int numEvalLines = tokenizer.countTokens(); 870 thread.fThreadCode = new String[fCode.length + numEvalLines + 1]; 871 System.arraycopy(fCode, 0, thread.fThreadCode, 0, fCode.length); 872 for (int i = 0; i < numEvalLines; i++) { 873 String line = tokenizer.nextToken(); 874 StringBuilder lineBuf = new StringBuilder(line.length()); 875 Matcher matcher = fPackPattern.matcher(line); 876 int lastMatchEnd = 0; 877 while (matcher.find()) { 878 lineBuf.append(line.substring(lastMatchEnd, matcher.start())); 879 String charCode = line.substring(matcher.start() + 1, matcher.start() + 3); 880 try { 881 lineBuf.append((char) Integer.parseInt(charCode, 16)); 882 } catch (NumberFormatException e) { 883 } 884 lastMatchEnd = matcher.end(); 885 } 886 if (lastMatchEnd < line.length()) { 887 lineBuf.append(line.substring(lastMatchEnd)); 888 } 889 thread.fThreadCode[fCode.length + i] = lineBuf.toString(); 890 } 891 thread.fThreadCode[fCode.length + numEvalLines] = "xyzzy"; //$NON-NLS-1$ 892 thread.fThreadLabels = mapLabels(fCode); 893 894 thread.fSavedPC = thread.fCurrentFrame.fPC; 895 thread.fCurrentFrame.fPC = fCode.length; 896 thread.fPerformingEval = true; 897 898 thread.fSuspend = null; 899 900 sendCommandResponse("ok\n"); //$NON-NLS-1$ 901 902 sendDebugEvent("resumed " + thread.fID + " eval", false); //$NON-NLS-1$ //$NON-NLS-2$ 903 } 904 debugEventStop(Args args)905 void debugEventStop(Args args) { 906 String event = args.getNextStringArg(); 907 int stop = args.getNextIntArg(); 908 fEventStops.put(event, Boolean.valueOf(stop > 0)); 909 sendCommandResponse("ok\n"); //$NON-NLS-1$ 910 } 911 debugTerminate()912 void debugTerminate() { 913 sendCommandResponse("ok\n"); //$NON-NLS-1$ 914 sendDebugEvent("vmterminated", false); //$NON-NLS-1$ 915 System.exit(0); 916 } 917 debugFrame(Args args)918 void debugFrame(Args args) { 919 PDAThread thread = args.getThreadArg(); 920 if (thread == null) { 921 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 922 return; 923 } 924 925 int sfnumber = args.getNextIntArg(); 926 Frame frame = null; 927 if (sfnumber >= thread.fFrames.size()) { 928 frame = thread.fCurrentFrame; 929 } else { 930 frame = thread.fFrames.get(sfnumber); 931 } 932 sendCommandResponse(printFrame(frame) + "\n"); //$NON-NLS-1$ 933 } 934 935 /** 936 * @param args 937 */ debugGroups(Args args)938 void debugGroups(Args args) { 939 TreeSet<String> groups = new TreeSet<>(); 940 for (Iterator<Register> itr = fRegisters.values().iterator(); itr.hasNext();) { 941 Register reg = itr.next(); 942 groups.add(reg.fGroup); 943 } 944 StringBuilder response = new StringBuilder(); 945 for (Iterator<String> itr = groups.iterator(); itr.hasNext();) { 946 response.append(itr.next()); 947 response.append('|'); 948 } 949 response.append('\n'); 950 sendCommandResponse(response.toString()); 951 } 952 debugPopData(Args args)953 void debugPopData(Args args) { 954 PDAThread thread = args.getThreadArg(); 955 if (thread == null) { 956 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 957 return; 958 } 959 960 thread.fStack.pop(); 961 sendCommandResponse("ok\n"); //$NON-NLS-1$ 962 } 963 debugPushData(Args args)964 void debugPushData(Args args) { 965 PDAThread thread = args.getThreadArg(); 966 if (thread == null) { 967 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 968 return; 969 } 970 971 Object val = args.getNextIntOrStringArg(); 972 thread.fStack.push(val); 973 sendCommandResponse("ok\n"); //$NON-NLS-1$ 974 } 975 debugRegisters(Args args)976 void debugRegisters(Args args) { 977 String group = args.getNextStringArg(); 978 979 StringBuilder response = new StringBuilder(); 980 for (Iterator<Register> itr = fRegisters.values().iterator(); itr.hasNext();) { 981 Register reg = itr.next(); 982 if (group.equals(reg.fGroup)) { 983 response.append(reg.fName); 984 response.append(' '); 985 response.append(reg.fIsWriteable); 986 for (Iterator<BitField> itr2 = reg.fBitFields.values().iterator(); itr2.hasNext();) { 987 BitField bitField = itr2.next(); 988 response.append('|'); 989 response.append(bitField.fName); 990 response.append(' '); 991 response.append(bitField.fBitOffset); 992 response.append(' '); 993 response.append(bitField.fBitCount); 994 response.append(' '); 995 for (Iterator<Entry<String, Integer>> itr3 = bitField.fMnemonics.entrySet().iterator(); itr3.hasNext();) { 996 Entry<String, Integer> mnemonicEntry = itr3.next(); 997 response.append(mnemonicEntry.getKey()); 998 response.append(' '); 999 response.append(mnemonicEntry.getValue()); 1000 response.append(' '); 1001 } 1002 } 1003 1004 response.append('#'); 1005 } 1006 } 1007 response.append('\n'); 1008 sendCommandResponse(response.toString()); 1009 } 1010 1011 /** 1012 * @param args 1013 */ debugRestart(Args args)1014 void debugRestart(Args args) { 1015 fSuspendVM = "restart"; //$NON-NLS-1$ 1016 1017 for (Iterator<Integer> itr = fThreads.keySet().iterator(); itr.hasNext();) { 1018 Integer id = itr.next(); 1019 sendDebugEvent("exited " + id, false); //$NON-NLS-1$ 1020 } 1021 fThreads.clear(); 1022 1023 int id = fNextThreadId++; 1024 fThreads.put(Integer.valueOf(id), new PDAThread(id, "main", 0)); //$NON-NLS-1$ 1025 sendDebugEvent("started " + id, false); //$NON-NLS-1$ 1026 1027 fRegisters.clear(); 1028 1029 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1030 } 1031 debugResume(Args args)1032 void debugResume(Args args) { 1033 PDAThread thread = args.getThreadArg(); 1034 if (thread == null) { 1035 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 1036 return; 1037 } 1038 if (fSuspendVM != null) { 1039 sendCommandResponse("error: cannot resume thread when vm is suspended\n"); //$NON-NLS-1$ 1040 return; 1041 } 1042 if (thread.fSuspend == null) { 1043 sendCommandResponse("error: thread already running\n"); //$NON-NLS-1$ 1044 return; 1045 } 1046 1047 thread.fSuspend = null; 1048 sendDebugEvent("resumed " + thread.fID + " client", false); //$NON-NLS-1$ //$NON-NLS-2$ 1049 1050 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1051 } 1052 debugSetBreakpoint(Args args)1053 void debugSetBreakpoint(Args args) { 1054 int line = args.getNextIntArg(); 1055 int stopVM = args.getNextIntArg(); 1056 1057 fBreakpoints.put(Integer.valueOf(line), Boolean.valueOf(stopVM != 0)); 1058 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1059 } 1060 debugSetData(Args args)1061 void debugSetData(Args args) { 1062 PDAThread thread = args.getThreadArg(); 1063 if (thread == null) { 1064 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 1065 return; 1066 } 1067 1068 int offset = args.getNextIntArg(); 1069 Object val = args.getNextIntOrStringArg(); 1070 1071 if (offset < thread.fStack.size()) { 1072 thread.fStack.set(offset, val); 1073 } else { 1074 thread.fStack.add(0, val); 1075 } 1076 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1077 } 1078 debugSetVariable(Args args)1079 void debugSetVariable(Args args) { 1080 PDAThread thread = args.getThreadArg(); 1081 if (thread == null) { 1082 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 1083 return; 1084 } 1085 1086 int sfnumber = args.getNextIntArg(); 1087 String var = args.getNextStringArg(); 1088 Object val = args.getNextIntOrStringArg(); 1089 while (args.hasNextArg()) { 1090 val = val + " " + args.getNextStringArg(); //$NON-NLS-1$ 1091 } 1092 1093 if (sfnumber >= thread.fFrames.size()) { 1094 thread.fCurrentFrame.set(var, val); 1095 } else { 1096 thread.fFrames.get(sfnumber).set(var, val); 1097 } 1098 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1099 } 1100 debugStack(Args args)1101 void debugStack(Args args) { 1102 PDAThread thread = args.getThreadArg(); 1103 if (thread == null) { 1104 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 1105 return; 1106 } 1107 1108 StringBuilder result = new StringBuilder(); 1109 1110 for (Iterator<Frame> itr = thread.fFrames.iterator(); itr.hasNext();) { 1111 Frame frame = itr.next(); 1112 result.append(printFrame(frame)); 1113 result.append('#'); 1114 } 1115 result.append(printFrame(thread.fCurrentFrame)); 1116 result.append('\n'); 1117 sendCommandResponse(result.toString()); 1118 } 1119 debugStackDepth(Args args)1120 void debugStackDepth(Args args) { 1121 PDAThread thread = args.getThreadArg(); 1122 if (thread == null) { 1123 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 1124 return; 1125 } 1126 sendCommandResponse( (thread.fFrames.size() + 1) + "\n" ); //$NON-NLS-1$ 1127 } 1128 1129 1130 /** 1131 * The stack frame output is: frame # frame # frame ... where each frame is: 1132 * filename | line number | function name | var | var | var | var ... 1133 */ printFrame(Frame frame)1134 private String printFrame(Frame frame) { 1135 StringBuilder buf = new StringBuilder(); 1136 buf.append(fFilename); 1137 buf.append('|'); 1138 buf.append(frame.fPC); 1139 buf.append('|'); 1140 buf.append(frame.fFunction); 1141 for (Iterator<String> itr = frame.fLocalVariables.keySet().iterator(); itr.hasNext();) { 1142 String var = itr.next(); 1143 if (var.indexOf('.') == -1) { 1144 buf.append('|'); 1145 buf.append(var); 1146 } 1147 } 1148 return buf.toString(); 1149 } 1150 debugState(Args args)1151 void debugState(Args args) { 1152 PDAThread thread = args.getThreadArg(); 1153 String response = null; 1154 if (thread == null) { 1155 response = fSuspendVM == null ? "running" : fSuspendVM; //$NON-NLS-1$ 1156 } else if (fSuspendVM != null) { 1157 response = "vm"; //$NON-NLS-1$ 1158 } else { 1159 response = thread.fSuspend == null ? "running" : thread.fSuspend; //$NON-NLS-1$ 1160 } 1161 sendCommandResponse(response + "\n"); //$NON-NLS-1$ 1162 } 1163 debugStep(Args args)1164 void debugStep(Args args) { 1165 PDAThread thread = args.getThreadArg(); 1166 if (thread == null) { 1167 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 1168 return; 1169 } 1170 1171 // Set suspend to null to allow the debug loop to exit back to the 1172 // instruction loop and thus run an instruction. However, we want to 1173 // come back to the debug loop right away, so the step flag is set to 1174 // true which will cause the suspend flag to get set to true when we 1175 // get to the next instruction. 1176 if (fSuspendVM != null) { 1177 // All threads are suspended, so suspend all threads again when 1178 // step completes. 1179 fSuspendVM = null; 1180 fStepVM = true; 1181 // Also mark the thread that initiated the step to mark it as 1182 // the triggering thread when suspending. 1183 thread.fStep = true; 1184 } else { 1185 if (thread.fSuspend == null) { 1186 sendCommandResponse("error: thread already running\n"); //$NON-NLS-1$ 1187 return; 1188 } 1189 thread.fSuspend = null; 1190 thread.fStep = true; 1191 sendDebugEvent("resumed " + thread.fID + " step", false); //$NON-NLS-1$ //$NON-NLS-2$ 1192 } 1193 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1194 } 1195 debugStepReturn(Args args)1196 void debugStepReturn(Args args) { 1197 PDAThread thread = args.getThreadArg(); 1198 if (thread == null) { 1199 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 1200 return; 1201 } 1202 1203 if (fSuspendVM != null) { 1204 fSuspendVM = null; 1205 fStepReturnVM = true; 1206 thread.fStepReturn = true; 1207 } else { 1208 if (thread.fSuspend == null) { 1209 sendCommandResponse("error: thread running\n"); //$NON-NLS-1$ 1210 return; 1211 } 1212 thread.fSuspend = null; 1213 thread.fStepReturn = true; 1214 sendDebugEvent("resumed " + thread.fID + " step", false); //$NON-NLS-1$ //$NON-NLS-2$ 1215 } 1216 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1217 } 1218 debugSuspend(Args args)1219 void debugSuspend(Args args) { 1220 PDAThread thread = args.getThreadArg(); 1221 if (thread == null) { 1222 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 1223 return; 1224 } 1225 if (fSuspendVM != null) { 1226 sendCommandResponse("error: vm already suspended\n"); //$NON-NLS-1$ 1227 return; 1228 } 1229 if (thread.fSuspend != null) { 1230 sendCommandResponse("error: thread already suspended\n"); //$NON-NLS-1$ 1231 return; 1232 } 1233 1234 thread.fSuspend = "client"; //$NON-NLS-1$ 1235 sendDebugEvent("suspended " + thread.fID + " client", false); //$NON-NLS-1$ //$NON-NLS-2$ 1236 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1237 } 1238 debugThreads()1239 void debugThreads() { 1240 StringBuilder response = new StringBuilder(); 1241 for (Iterator<Integer> itr = fThreads.keySet().iterator(); itr.hasNext();) { 1242 response.append(itr.next()); 1243 response.append(' '); 1244 } 1245 sendCommandResponse(response.toString().trim() + "\n"); //$NON-NLS-1$ 1246 } 1247 debugVar(Args args)1248 void debugVar(Args args) { 1249 PDAThread thread = args.getThreadArg(); 1250 if (thread == null) { 1251 sendCommandResponse("error: invalid thread\n"); //$NON-NLS-1$ 1252 return; 1253 } 1254 1255 int sfnumber = args.getNextIntArg(); 1256 String var = args.getNextStringArg(); 1257 1258 Frame frame = sfnumber >= thread.fFrames.size() 1259 ? thread.fCurrentFrame : (Frame)thread.fFrames.get(sfnumber); 1260 1261 Object val = frame.get(var); 1262 if (val == null) { 1263 sendCommandResponse("error: variable undefined\n"); //$NON-NLS-1$ 1264 } else { 1265 sendCommandResponse(val + "\n"); //$NON-NLS-1$ 1266 } 1267 } 1268 debugVMResume()1269 void debugVMResume() { 1270 if (fSuspendVM == null) { 1271 sendCommandResponse("error: vm already running\n"); //$NON-NLS-1$ 1272 return; 1273 } 1274 1275 fSuspendVM = null; 1276 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1277 } 1278 debugVMSuspend()1279 void debugVMSuspend() { 1280 if (fSuspendVM != null) { 1281 sendCommandResponse("error: vm already suspended\n"); //$NON-NLS-1$ 1282 return; 1283 } 1284 1285 fSuspendVM = "client"; //$NON-NLS-1$ 1286 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1287 } 1288 debugWatch(Args args)1289 void debugWatch(Args args) { 1290 String funcAndVar = args.getNextStringArg(); 1291 int flags = args.getNextIntArg(); 1292 fWatchpoints.put(funcAndVar, Integer.valueOf(flags)); 1293 sendCommandResponse("ok\n"); //$NON-NLS-1$ 1294 } 1295 1296 /** 1297 * @param thread 1298 * @param args 1299 */ iAdd(PDAThread thread, Args args)1300 void iAdd(PDAThread thread, Args args) { 1301 Object val1 = thread.fStack.pop(); 1302 Object val2 = thread.fStack.pop(); 1303 if (val1 instanceof Integer && val2 instanceof Integer) { 1304 int intVal1 = ((Integer) val1).intValue(); 1305 int intVal2 = ((Integer) val2).intValue(); 1306 thread.fStack.push( Integer.valueOf(intVal1 + intVal2) ); 1307 } else { 1308 thread.fStack.push( Integer.valueOf(-1) ); 1309 } 1310 } 1311 iBranchNotZero(PDAThread thread, Args args)1312 void iBranchNotZero(PDAThread thread, Args args) { 1313 Object val = thread.fStack.pop(); 1314 if (val instanceof Integer && ((Integer) val).intValue() != 0) { 1315 String label = args.getNextStringArg(); 1316 if (thread.fThreadLabels.containsKey(label)) { 1317 thread.fCurrentFrame.fPC = thread.fThreadLabels.get(label).intValue(); 1318 } else { 1319 sendDebugEvent("no such label " + label, true); //$NON-NLS-1$ 1320 if ( fEventStops.get("nosuchlabel").booleanValue() ) { //$NON-NLS-1$ 1321 fSuspendVM = thread.fID + " event nosuchlabel"; //$NON-NLS-1$ 1322 thread.fStack.push(val); 1323 thread.fCurrentFrame.fPC--; 1324 } 1325 } 1326 } 1327 } 1328 iCall(PDAThread thread, Args args)1329 void iCall(PDAThread thread, Args args) { 1330 String label = args.getNextStringArg(); 1331 if (thread.fThreadLabels.containsKey(label)) { 1332 thread.fFrames.add(thread.fCurrentFrame); 1333 thread.fCurrentFrame = new Frame(label, thread.fThreadLabels.get(label).intValue()); 1334 } else { 1335 sendDebugEvent("no such label " + label, true); //$NON-NLS-1$ 1336 if ( fEventStops.get("nosuchlabel").booleanValue() ) { //$NON-NLS-1$ 1337 fSuspendVM = thread.fID + " event nosuchlabel"; //$NON-NLS-1$ 1338 thread.fCurrentFrame.fPC--; 1339 } 1340 } 1341 } 1342 1343 /** 1344 * @param thread 1345 * @param args 1346 */ iDec(PDAThread thread, Args args)1347 void iDec(PDAThread thread, Args args) { 1348 Object val = thread.fStack.pop(); 1349 if (val instanceof Integer) { 1350 val = Integer.valueOf(((Integer) val).intValue() - 1); 1351 } 1352 thread.fStack.push(val); 1353 } 1354 1355 /** 1356 * @param thread 1357 * @param args 1358 */ iDef(PDAThread thread, Args args)1359 void iDef(PDAThread thread, Args args) { 1360 String type = args.getNextStringArg(); 1361 1362 String name = args.getNextStringArg(); 1363 String regName = getRegisterPartOfName(name); 1364 String bitFieldName = getBitFieldPartOfName(name); 1365 1366 if ("register".equals(type)) { //$NON-NLS-1$ 1367 Register reg = new Register(regName); 1368 reg.fGroup = args.getNextStringArg(); 1369 fRegisters.put(regName, reg); 1370 reg.fIsWriteable = args.getNextBooleanArg(); 1371 } else if ("bitfield".equals(type)) { //$NON-NLS-1$ 1372 Register reg = fRegisters.get(regName); 1373 if (reg == null) { 1374 return; 1375 } 1376 BitField bitField = new BitField(bitFieldName); 1377 bitField.fBitOffset = args.getNextIntArg(); 1378 bitField.fBitCount = args.getNextIntArg(); 1379 reg.fBitFields.put(bitFieldName, bitField); 1380 } else if ("mnemonic".equals(type)) { //$NON-NLS-1$ 1381 Register reg = fRegisters.get(regName); 1382 if (reg == null) { 1383 return; 1384 } 1385 BitField bitField = reg.fBitFields.get(bitFieldName); 1386 if (bitField == null) { 1387 return; 1388 } 1389 bitField.fMnemonics.put(args.getNextStringArg(), Integer.valueOf(args.getNextIntArg())); 1390 } 1391 sendDebugEvent("registers", false); //$NON-NLS-1$ 1392 } 1393 getRegisterPartOfName(String name)1394 private String getRegisterPartOfName(String name) { 1395 if (name.startsWith("$")) { //$NON-NLS-1$ 1396 int end = name.indexOf('.'); 1397 end = end != -1 ? end : name.length(); 1398 return name.substring(1, end); 1399 } 1400 return null; 1401 } 1402 getBitFieldPartOfName(String name)1403 private String getBitFieldPartOfName(String name) { 1404 int start = name.indexOf('.'); 1405 if (name.startsWith("$") && start != -1) { //$NON-NLS-1$ 1406 return name.substring(start + 1, name.length()); 1407 } 1408 return null; 1409 } 1410 1411 /** 1412 * @param thread 1413 * @param args 1414 */ iDup(PDAThread thread, Args args)1415 void iDup(PDAThread thread, Args args) { 1416 Object val = thread.fStack.pop(); 1417 thread.fStack.push(val); 1418 thread.fStack.push(val); 1419 } 1420 iExec(PDAThread thread, Args args)1421 void iExec(PDAThread thread, Args args) { 1422 String label = args.getNextStringArg(); 1423 if (fLabels.containsKey(label)) { 1424 int id = fNextThreadId++; 1425 fThreads.put( Integer.valueOf(id), new PDAThread(id, label, fLabels.get(label).intValue()) ); 1426 sendDebugEvent("started " + id, false); //$NON-NLS-1$ 1427 } else { 1428 sendDebugEvent("no such label " + label, true); //$NON-NLS-1$ 1429 if ( fEventStops.get("nosuchlabel").booleanValue() ) { //$NON-NLS-1$ 1430 thread.fSuspend = "event nosuchlabel"; //$NON-NLS-1$ 1431 thread.fCurrentFrame.fPC--; 1432 } 1433 } 1434 } 1435 1436 /** 1437 * @param thread 1438 * @param args 1439 */ iHalt(PDAThread thread, Args args)1440 void iHalt(PDAThread thread, Args args) { 1441 thread.fRun = false; 1442 } 1443 1444 /** 1445 * @param thread 1446 * @param args 1447 */ iOutput(PDAThread thread, Args args)1448 void iOutput(PDAThread thread, Args args) { 1449 System.out.println(thread.fStack.pop()); 1450 } 1451 iPop(PDAThread thread, Args args)1452 void iPop(PDAThread thread, Args args) { 1453 String arg = args.getNextStringArg(); 1454 if (arg.startsWith("$")) { //$NON-NLS-1$ 1455 String var = arg.substring(1); 1456 thread.fCurrentFrame.set(var, thread.fStack.pop()); 1457 String key = thread.fCurrentFrame.fFunction + "::" + var; //$NON-NLS-1$ 1458 if ( fWatchpoints.containsKey(key) && (fWatchpoints.get(key).intValue() & 2) != 0 ) { 1459 fSuspendVM = thread.fID + " watch write " + key; //$NON-NLS-1$ 1460 } 1461 } else { 1462 thread.fStack.pop(); 1463 } 1464 } 1465 iPush(PDAThread thread, Args args)1466 void iPush(PDAThread thread, Args args) { 1467 String arg = args.getNextStringArg(); 1468 while (arg.length() != 0) { 1469 if (arg.startsWith("$")) { //$NON-NLS-1$ 1470 String var = arg.substring(1); 1471 Object val = thread.fCurrentFrame.get(var); 1472 if (val == null) 1473 { 1474 val = "<undefined>"; //$NON-NLS-1$ 1475 } 1476 thread.fStack.push(val); 1477 String key = thread.fCurrentFrame.fFunction + "::" + var; //$NON-NLS-1$ 1478 if (fWatchpoints.containsKey(key) && (fWatchpoints.get(key).intValue() & 1) != 0) { 1479 fSuspendVM = thread.fID + " watch read " + key; //$NON-NLS-1$ 1480 } 1481 } else { 1482 Object val = arg; 1483 if (args.hasNextArg()) { 1484 while (args.hasNextArg()) { 1485 val = val + " " + args.getNextStringArg(); //$NON-NLS-1$ 1486 } 1487 } else { 1488 try { 1489 val = Integer.valueOf(arg); 1490 } catch (NumberFormatException e) { 1491 } 1492 } 1493 thread.fStack.push(val); 1494 } 1495 1496 arg = args.getNextStringArg(); 1497 } 1498 } 1499 1500 /** 1501 * @param thread 1502 * @param args 1503 */ iReturn(PDAThread thread, Args args)1504 void iReturn(PDAThread thread, Args args) { 1505 if (!thread.fFrames.isEmpty()) { 1506 thread.fCurrentFrame = thread.fFrames.remove(thread.fFrames.size() - 1); 1507 } else { 1508 // Execution returned from the top frame, which means this thread 1509 // should exit. 1510 thread.fRun = false; 1511 } 1512 } 1513 iVar(PDAThread thread, Args args)1514 void iVar(PDAThread thread, Args args) { 1515 String var = args.getNextStringArg(); 1516 thread.fCurrentFrame.set(var, Integer.valueOf(0)); 1517 } 1518 1519 /** 1520 * @param thread 1521 * @param args 1522 */ iInternalEndEval(PDAThread thread, Args args)1523 void iInternalEndEval(PDAThread thread, Args args) { 1524 Object result = thread.fStack.pop(); 1525 thread.fThreadCode = fCode; 1526 thread.fThreadLabels = fLabels; 1527 thread.fCurrentFrame.fPC = thread.fSavedPC; 1528 sendDebugEvent("evalresult " + result, false); //$NON-NLS-1$ 1529 thread.fSuspend = "eval"; //$NON-NLS-1$ 1530 thread.fPerformingEval = false; 1531 } 1532 1533 } 1534