content: /*
   * Created on Nov 16, 2004
   *
   * To change the template for this generated file go to
   * Window - Preferences - Java - Code Generation - Code and Comments
   */
  package com.zylin.zpu.simulator.gdb;
  
  import java.io.IOException;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import com.zylin.zpu.simulator.exceptions.BadPacketException;
  import com.zylin.zpu.simulator.exceptions.CPUException;
  import com.zylin.zpu.simulator.exceptions.EndSessionException;
  import com.zylin.zpu.simulator.exceptions.GDBServerException;
  import com.zylin.zpu.simulator.exceptions.MemoryAccessException;
  import com.zylin.zpu.simulator.exceptions.NoAckException;
  import com.zylin.zpu.simulator.exceptions.UnknownPacketException;
  
  
  /** all packet related operations */
  class Packet
  {
  	private final GDBServer server;
  	
  	Packet(GDBServer server)
  	{
  		this.server = server;
          reply=new StringBuffer();
  	}
  	
  	void receive() throws IOException, GDBServerException, EndSessionException
  	{
  		int t;
  		/* we spool until we see a $ */
  		this.server.expect('$');
  		
  		StringBuffer packet=new StringBuffer();
  	
  		int cc=0;
  		for (;;)
  		{
  			int t1;
  			t1=this.server.read();
  			t = t1;
  			if (t==0x7d)
  			{
  				int t2;
  				t2=this.server.read();
  				/* the next char is escaped after a GDB specific scheme. See
  				 * gdb/gdb/remote.c */
  				t = t2;
  				t^=0x20;
  			} else
  			{
  				if (t=='#')
  				{
  					break;
  				}
  			}
  			
  			cc+=t;
  			
  			packet.append((char)t);
  		}
  		cc&=0xff;
  		
  		String checkSum;
  		checkSum=""+(char)this.server.read()+(char)this.server.read();
  		int readCheckSum;
  		readCheckSum=Integer.parseInt(checkSum, 16);
  		if (readCheckSum!=cc)
  		{
  			// error
  			dumpHex(packet.toString());
  			
  			this.server.write("-".getBytes());
  			throw new BadPacketException();
  		} else
  		{
  			// ack
  			this.server.write("+".getBytes());
  		}
  		
  		cmd=packet.toString();
  		this.server.print(GDBServer.PACKET, "Got " + number + ": #$" + cmd + "#" + checkSum); 
  		origCmd=cmd;
  	}
  	
  	void parseAndExecute() throws IOException, EndSessionException
  	{
      	boolean silent=false;
  	    try
  		{
  			if (checkPrefix("g"))
  			{
  				readRegisters();
  			} else if (checkPrefix("?"))
  			{
  				querySignal();
  			} else if (checkPrefix("s"))
  			{
  				doStep();
  			} else if (checkPrefix("m"))
  			{
  				try
  				{
  					readMemory();
  				} catch (CPUException e)
                  {
                      silent=true; // happens all the time while hovering over variables in the GUI
                      throw e;
                  }
  			} else if (checkPrefix("c"))
  			{
  				continueExecution();
  			} else if (checkPrefix("M"))
  			{
  				writeMemory();
  			} else if (checkPrefix("z4"))
  			{
  				disableAccessWatchPoint();
  			} else if (checkPrefix("Z4"))
  			{
  				enableAccessWatchPoint();
  			} else if (checkPrefix("k"))
  			{
  				/* we must send a reply, but not wait for ack before we shut down
  				   the connection.
  				*/
  			    server.alive=false;
  			    reply("OK");
  			} else
  			{
  				throw new UnknownPacketException();
  			}
  		} catch (UnknownPacketException e)
  		{
  			this.server.print(GDBServer.UNKNOWN, "Unknown packet: " + origCmd);
  			// empty reply to unknown packets
  		} catch (CPUException e)
          {
              if (!silent)
              {
                  this.server.print(GDBServer.CPUEXCEPTION, "Exception handling GDB request");
                  if (GDBServer.CPUEXCEPTION)
                  {
                      e.printStackTrace();
                  }
              }               
              reply("E01");
          } catch (GDBServerException e)
          {
              e.printStackTrace();
              reply("E01");
          }  catch (RuntimeException e)
  		{
  			e.printStackTrace();
  			reply("E01");
  		} 
          
  		sendReply();
  	}
  
  	private void checkEmpty() throws GDBServerException
  	{
  		if (cmd.length()>0)
  		{
  			throw new GDBServerException();
  		}
  	}
  	private void dumpHex(String arrayList2)
  	{
  		for (int i=0; i<arrayList2.length(); i++)
  		{
  			System.out.println(this.server.formatHex(arrayList2.charAt(i), "00"));
  		}
  	}
  	/**
  	 * @param packetString
  	 * @param string
  	 * @return
  	 */
  	private boolean checkPrefix(String string)
  	{
  		if (cmd.length() < string.length())
  		{
  			return false;
  		} else
  		{
  			return cmd.substring(0, string.length()).equals(string);
  		}
  	}
  	/**
  	 * @throws GDBServerException
  	 * @throws IOException 
  	 * @throws MemoryAccessException
  	 * 
  	 */
  	private void continueExecution() throws GDBServerException
  	{
  		extractString("c");
  		try
  		{
  			if (!isEmpty())
  			{
  				int pc=extractInteger();
  				this.server.simulator.setPc(pc);
  			}
  			checkEmpty();
  			this.server.simulator.cont();
  		} catch (MemoryAccessException e)
  		{
  			if (GDBServer.IGNOREDEXCEPTIONS)
  			{
  				e.printStackTrace();
  			}
  		}
  		reply("S05");
  	}
  	private void doStep()
  	{
  		this.server.simulator.step();
  		reply("S05");
  	}
  	protected int extractInteger() throws GDBServerException
  	{
  		String number;
  		Pattern p=Pattern.compile("(\\-?[0-9a-fA-F]+)");
  		Matcher m = p.matcher(cmd);
  		if (!m.find())
  		{
  			throw new GDBServerException();
  		}
  		number=m.group();
  		extractString(number);
  		
  		try
  		{
  			return (int)Long.parseLong(number, 16);
  		} catch (NumberFormatException e)
  		{
  			throw new GDBServerException(e);
  		}
  	}
  	/**
  	 * @param string
  	 * @throws GDBServerException
  	 */
  	private void extractString(String string) throws GDBServerException
  	{
  		if (!checkPrefix(string))
  		{
  			throw new GDBServerException();
  		}
  		stripStart(string.length());
  	}
  	/**
  	 * @throws GDBServerException
  	 * 
  	 */
  	private void readMemory() throws CPUException, GDBServerException
  	{
  		extractString("m");
  		int address=extractInteger();
  		extractString(",");
  		int length=extractInteger();
  		checkEmpty();
  		
  		for (int i=0; i<length; i++)
  		{
  			reply(this.server.formatHex(this.server.simulator.readByte(address+i), "00"));
  		}
  	}
  	/**
  	 * 
  	 */
  	private void readRegisters()  throws CPUException
  	{
  		for (int i=0; i<this.server.simulator.getREGNUM(); i++)
  		{
  			reply(this.server.printHex(this.server.simulator.getReg(i))); 
  		}
  	}
  	private void writeMemory() throws GDBServerException, MemoryAccessException
  	{
  		extractString("M");
  		int address=extractInteger();
  		extractString(",");
  		int length=extractInteger();
  		extractString(":");
  		
  		for (int i=0; i<length; i++)
  		{
  			String t;
  			t=cmd.substring(i*2, i*2+2);
  			int val;
  			val=Integer.parseInt(t, 16);
  			this.server.simulator.writeByte(address+i, val);
  		}
  		reply("OK");
  		
  	}
  	
  	private void enableAccessWatchPoint() throws GDBServerException, CPUException 
  	{
  		extractString("Z4");
  		extractString(",");
  		int address=extractInteger();
  		extractString(",");
  		int length=extractInteger();
  		checkEmpty();
  		server.simulator.enableAccessWatchPoint(address, length);
  		
  		reply("OK");
  	}
  
  	private void disableAccessWatchPoint() throws GDBServerException, CPUException 
  	{
  		extractString("z4");
  		extractString(",");
  		int address=extractInteger();
  		extractString(",");
  		int length=extractInteger();
  		checkEmpty();
  		server.simulator.disableAccessWatchPoint(address, length);
  		
  		reply("OK");
  	}
  
  	
  	private void stripStart(int length)
  	{
  		cmd=cmd.substring(length);
  	}
  	private boolean isEmpty() 
  	{
  		return cmd.length()==0;
  	}
  	/**
  	 * @param string
  	 */
  	protected void reply(String string)
  	{
  		reply.append(string);
  	}
  	void sendReply()
  	{
  		// a bit easier to debug if we can see the entire string.
  		StringBuffer buffer = new StringBuffer();
  		buffer.append("$");
  		number++;
  		String replyString = reply.toString();
  		buffer.append(replyString);
  		byte[] data = replyString.toString().getBytes();
  		int csum = 0;
  		for (int i = 0; i < data.length; i++)
  		{
  			csum += data[i];
  		}
  		csum &= 0xff;
  		buffer.append("#");
  		String t = Integer.toHexString(csum);
  		if (t.length() == 1)
  		{
  			t = "0" + t;
  		}
  		buffer.append(t);
  		this.server.print(GDBServer.REPLY, "Reply " + number + " : " + buffer.toString());
  		try
  		{
  			this.server.write(buffer.toString().getBytes());
  		} catch (IOException e)
  		{
  			throw new RuntimeException(e);
  		}
  		
  		if (server.alive)
  		{
  			/* check for ack. */
  			int ack;
  			try
  			{
  				ack = (char)this.server.read();
  			} catch (IOException e)
  			{
  				throw new RuntimeException(e);
  			}
  			if (ack == '+')
  			{
  				return;
  			}
  			this.server.print(GDBServer.MINIMAL, "Retry");
  			
  			throw new NoAckException();
  		}
  		reply=new StringBuffer();
  	}
  	
  	private void querySignal()
  	{
  		// SIGINT
  		//	reply("S02");
  		reply("S05");
  	}
  	protected String cmd;
  	private int number;
  	private StringBuffer reply;
  	private String origCmd;
      int syscallErrno;
      int syscallRetval;
  
  
      
      void invokeSyscall(String string, int argNum, String types) throws IOException, NoAckException, GDBServerException, EndSessionException, CPUException
      {
          string="F"+string;
          
          int j=0;
          for (int i=0; i<argNum; i++)
          {
              string+=",";
              string+=Integer.toHexString(server.getSyscallArg(j));
              j++;
              if (types.charAt(i)=='s')
              {
                  string+="/" + Integer.toHexString(server.getSyscallArg(j));
                  j++;
              }
          }
  
          reply(string);
          sendReply();
          for (;;)
          {
              Packet packet=new Packet(server);
              packet.receive();
              if (packet.checkPrefix("F"))
              {
                  /* this is the reply we are waiting for */
                  packet.extractString("F");
                  syscallRetval=packet.extractInteger();
                  syscallErrno=0;
                  if (packet.checkPrefix(","))
                  {
                      /* errno is optional */
                      packet.extractString(",");
                      syscallErrno = packet.extractInteger();
                  }
                  break;
              } else
              {
                  /* something else... */
                  try
                  {
                      packet.parseAndExecute();
                      packet.sendReply();
                  } catch (IOException e)
                  {
                      e.printStackTrace();
                  } catch (EndSessionException e)
                  {
                      e.printStackTrace();
                  } catch (RuntimeException e)
                  {
                      e.printStackTrace();
                  }
              }
          }
      }
  }