/******************************************************************************* * Copyright (c) 2005, 2009 Wind River Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bjorn Freeman-Benson - initial API and implementation * Pawel Piech (Wind River) - ported PDA Virtual Machine to Java (Bug 261400) *******************************************************************************/ package org.eclipse.debug.examples.pdavm; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.StringWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Push Down Automata interpreter. * * @since 3.5 */ public class PDAVirtualMachine { static class Stack extends LinkedList { private static final long serialVersionUID = 1L; public Object pop() { return isEmpty() ? new Integer(0) : remove(size() - 1); } public void push(Object value) { add(value); } } static class Register { Register(String name) { fName = name; } String fName; String fGroup = ""; boolean fIsWriteable = true; Map fBitFields = new LinkedHashMap(0); int fValue; } static class BitField { BitField(String name) { fName = name; } String fName; int fBitOffset; int fBitCount; Map fMnemonics = new LinkedHashMap(0); } Map fRegisters = new LinkedHashMap(0); class Args { final String[] fArgs; int next = 0; Args(String[] args) { fArgs = args; } boolean hasNextArg() { return fArgs.length > next; } String getNextStringArg() { if (fArgs.length > next) { return fArgs[next++]; } return ""; } int getNextIntArg() { String arg = getNextStringArg(); try { return Integer.parseInt(arg); } catch (NumberFormatException e) { } return 0; } boolean getNextBooleanArg() { String arg = getNextStringArg(); try { return Boolean.getBoolean(arg); } catch (NumberFormatException e) { } return false; } Object getNextIntOrStringArg() { String arg = getNextStringArg(); try { return new Integer(arg); } catch (NumberFormatException e) { } return arg; } PDAThread getThreadArg() { int id = getNextIntArg(); return (PDAThread)fThreads.get( new Integer(id) ); } } class PDAThread { final int fID; /** The push down automata data stack (the data stack). */ final Stack fStack = new Stack(); /** * PDAThread copy of the code. It can differ from the program if * performing an evaluation. */ String[] fThreadCode; /** PDAThread copy of the labels. */ Map fThreadLabels; /** The stack of stack frames (the control stack) */ final List fFrames = new LinkedList(); /** Current stack frame (not includced in fFrames) */ Frame fCurrentFrame; /** * The run flag is true if the thread is running. If the run flag is * false, the thread exits the next time the main instruction loop runs. */ boolean fRun = true; String fSuspend = null; boolean fStep = false; boolean fStepReturn = false; int fSavedPC; boolean fPerformingEval = false; PDAThread(int id, String function, int pc) { fID = id; fCurrentFrame = new Frame(function, pc); fThreadCode = fCode; fThreadLabels = fLabels; } } final Map fThreads = new LinkedHashMap(); int fNextThreadId = 1; boolean fStarted = true; /** * The code is stored as an array of strings, each line of the source file * being one entry in the array. */ final String[] fCode; /** A mapping of labels to indicies in the code array */ final Map fLabels; /** Each stack frame is a mapping of variable names to values. */ class Frame { final Map fLocalVariables = new LinkedHashMap(); /** * The name of the function in this frame */ final String fFunction; /** * The current program counter in the frame the pc points to the next * instruction to be executed */ int fPC; Frame(String function, int pc) { fFunction = function; fPC = pc; } void set(String name, Object value) { if (name.startsWith("$")) { setRegisterValue(name, value); } else { fLocalVariables.put(name, value); } } Object get(String name) { if (name.startsWith("$")) { return getRegisterValue(name); } else { return fLocalVariables.get(name); } } } void setRegisterValue(String name, Object value) { Register reg = (Register)fRegisters.get(getRegisterPartOfName(name)); if (reg == null) return; String bitFieldName = getBitFieldPartOfName(name); if (bitFieldName != null) { BitField bitField = (BitField)reg.fBitFields.get(bitFieldName); if (bitField == null) return; Integer intValue = null; if (value instanceof Integer) { intValue = (Integer)value; } else if (value instanceof String) { intValue = (Integer)bitField.fMnemonics.get(value); } if (intValue != null) { int bitFieldMask = 2^(bitField.fBitCount - 1); int registerMask = ~(bitFieldMask << bitField.fBitOffset); int bitFieldValue = intValue.intValue() & bitFieldMask; reg.fValue = (reg.fValue & registerMask) | (bitFieldValue << bitField.fBitOffset); } } else if (value instanceof Integer) { reg.fValue = ((Integer)value).intValue(); } } Object getRegisterValue(String name) { Register reg = (Register)fRegisters.get(getRegisterPartOfName(name)); if (reg == null) return null; String bitFieldName = getBitFieldPartOfName(name); if (bitFieldName != null) { BitField bitField = (BitField)reg.fBitFields.get(bitFieldName); if (bitField == null) return null; int bitFieldMask = 2^(bitField.fBitCount - 1); int registerMask = bitFieldMask << bitField.fBitOffset; return new Integer( (reg.fValue & registerMask) >> bitField.fBitOffset ); } else { return new Integer(reg.fValue); } } /** * Breakpoints are stored per each each line of code. The boolean indicates * whether the whole VM should suspend or just the triggering thread. */ final Map fBreakpoints = new HashMap(); /** * The suspend flag is true if the VM should suspend running the program and * just listen for debug commands. */ String fSuspendVM; /** Flag indicating whether the debugger is performing a step. */ boolean fStepVM = false; /** Flag indicating whether the debugger is performing a step return */ boolean fStepReturnVM = false; int fSteppingThread = 0; /** Name of the pda program being debugged */ final String fFilename; /** The command line argument to start a debug session. */ final boolean fDebug; /** The port to listen for debug commands on */ final int fCommandPort; /** * Command socket for receiving debug commands and sending command responses */ Socket fCommandSocket; /** Command socket reader */ BufferedReader fCommandReceiveStream; /** Command socket write stream. */ OutputStream fCommandResponseStream; /** The port to send debug events to */ final int fEventPort; /** Event socket */ Socket fEventSocket; /** Event socket and write stream. */ OutputStream fEventStream; /** The eventstops table holds which events cause suspends and which do not. */ final Map fEventStops = new HashMap(); { fEventStops.put("unimpinstr", Boolean.FALSE); fEventStops.put("nosuchlabel", Boolean.FALSE); } /** * The watchpoints table holds watchpoint information. *

* variablename_stackframedepth => N *