content: /** 
   * Handles TCP/IP communication between simulator and GDB
   */
  
  package com.zylin.zpu.simulator.gdb;
  
  import java.io.IOException;
  import java.net.Socket;
  import java.nio.ByteBuffer;
  import java.nio.channels.SelectionKey;
  import java.nio.channels.Selector;
  import java.nio.channels.SocketChannel;
  import java.util.Iterator;
  
  import com.zylin.zpu.simulator.Host;
  import com.zylin.zpu.simulator.Sim;
  import com.zylin.zpu.simulator.SimApp;
  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.UnsupportedSyscallException;
  
  public class GDBServer implements Host 
  {
  	/* logging filter */
  	static final boolean UNKNOWN=false;
  	static final boolean ALL=false;
  	static final boolean CPUEXCEPTION = false;
  	static protected boolean MINIMAL=true;
  	static boolean PACKET=true;
  	static boolean REPLY=true;
  	static protected boolean IGNOREDEXCEPTIONS=false;
  	
  	
  	
  	protected Throwable packetException;
  	protected Object packetReady=new Object();
  	private Packet packet;
  	boolean done;
  	private Socket sc;
      public boolean alive;
      static private int sessionNr;
  	private SimApp app;
      Sim simulator;
      
      public GDBServer(Sim simulator, SimApp app)
      {
          this.simulator=simulator;
      	this.app=app;
      }
      
  	void print(boolean filter, String str)
  	{
  		if (filter)
  		{
  			System.out.println(str);
  		}
  	}
  	
  	/** infinite loop that waits for debug sessions to be initiated via TCP/IP */
  	public void gdbServer() throws MemoryAccessException, IOException, GDBServerException, EndSessionException 
  	{
  		sc=app.serverSocket.accept();
  		try
  		{
  			debugSession();
  		} catch (IOException e)
  		{
  			// the session failed...
  			if (IGNOREDEXCEPTIONS)
  			{
  				e.printStackTrace();
  			}
  		} catch (GDBServerException e)
  		{
  			// connect failed...
  			if (IGNOREDEXCEPTIONS)
  			{
  				e.printStackTrace();
  			}
  		} catch (EndSessionException e)
  		{
  		} catch (Throwable e)
  		{
  			// some terrible unforseen failure.
  			e.printStackTrace();
  		} finally
  		{
  			sc.close();
  		}
  	}
  
  
  	
  	protected void sleepABit()
  	{
  		try
  		{
  			// just to avoid locking up the machine in a busy loop when
  			// debugging the Simulator
  			Thread.sleep(2000);
  		} catch (InterruptedException e1)
  		{
  			e1.printStackTrace();
  		}
  	}
  
  	private void debugSession() throws IOException, GDBServerException, EndSessionException, MemoryAccessException 
  	{
  		print(MINIMAL, "GDB server waiting for connection " + sessionNr++ + "...");
  
          try
          {
              sessionStarted();
  
              expect('+'); // connection ack.
  
              sessionLoop();
          } finally
          {
  			print(MINIMAL, "Session ended");
          }
              
  	}
  
  	private void sessionStarted()
  	{
  		simulator.sessionStarted();
  		print(MINIMAL, "Session started");
  	}
  
  	
  	private void sessionLoop() throws IOException, EndSessionException
  	{
  		alive=true;
  		while (alive)
  		{
  			try
  			{
  				/* wait for new packet to arrive and notify the packet execution thread... */
  				packet=new Packet(this);
  				packet.receive();
  		
  				// During execution we can receive an abort/suspend command...
  				packet.parseAndExecute();
  				
  				if (!alive)
  				    throw new EndSessionException();
  			} catch (BadPacketException e)
  			{
  				// do nothing.
  				if (IGNOREDEXCEPTIONS)
  				{
  					e.printStackTrace();
  				}
  				sleepABit();
  			} catch (GDBServerException e)
  			{
  				if (IGNOREDEXCEPTIONS)
  				{
  					e.printStackTrace();
  				}
  				// continue processing packets
  				sleepABit();
  			}
  		}
  	}
  
  
  	
  
  	void expect(char nextChar) throws IOException, GDBServerException
  	{
  		int t = read();
  		if (t!=nextChar)
  		{
  			throw new BadPacketException();
  		}
  	}
  
  	int read() throws IOException
  	{
  		flush();
  		int t=sc.getInputStream().read();
  		if (t==-1)
  			throw new IOException();
  		return t;
  	}
  
  	/**
  	 * @param value
  	 * @return
  	 */
  	protected String printHex(int value)
  	{
  		return formatHex(value, "00000000");
  	}
  
  	/**
  	 * @param value
  	 * @param pad TODO
  	 * @return
  	 */
  	protected String formatHex(int value, String pad)
  	{
  		String t=Integer.toHexString(value);
  		if (t.length()>pad.length())
  		{
  			t=t.substring(0, pad.length());
  		}
  		return pad.substring(0, pad.length()-t.length())+t;
  	}
  
  	public void write(byte[] bytes) throws IOException
  	{
  		sc.getOutputStream().write(bytes);
  	}
  
  	void flush() throws IOException 
  	{
  		sc.getOutputStream().flush();
  	}
  
      
      private boolean enterSyscall;
  
  
      
      /* handle all sorts of IO calls, etc. by sending them to the
       */
      public void syscall(Sim s) throws CPUException
      {
          simulator.suspend();
          enterSyscall=true;
      }
  
  
      protected void performSyscall() 
      {
          enterSyscall=false;
          try
          {
              int id;
              id=simulator.getArg(1);
              Packet syscall;
              syscall=new Packet(this);
              switch (id)
              {
              case Host.SYS_write:
                  syscall.invokeSyscall("write", 3, "iii");
                  break;
              case Host.SYS_read:
                  syscall.invokeSyscall("read", 3, "iii");
                  break;
              case Host.SYS_lseek:
                  syscall.invokeSyscall("lseek", 3, "iii");
                  break;
              case Host.SYS_open:
                  syscall.invokeSyscall("open", 3, "sii");
                  break;
              case Host.SYS_close:
                  syscall.invokeSyscall("close", 1, "i");
                  break;
              case Host.SYS_fstat:
                  syscall.invokeSyscall("fstat", 2, "ii");
                  break;
              case Host.SYS_stat:
                  syscall.invokeSyscall("stat", 2, "si");
                  break;
              case Host.SYS_isatty:
                  syscall.invokeSyscall("isatty", 1, "i");
                  break;
              case Host.SYS_unlink:
                  syscall.invokeSyscall("unlink", 1, "s");
                  break;
              default:
                  simulator.suspend();
                  throw new UnsupportedSyscallException();
              }
              simulator.cpuWriteLong(simulator.getArg(0), syscall.syscallErrno);
              simulator.cpuWriteLong(0, syscall.syscallRetval);
          } catch (CPUException e)
          {
              e.printStackTrace();
          } catch (IOException e)
          {
              e.printStackTrace();
          } catch (GDBServerException e)
          {
              e.printStackTrace();
          } catch (EndSessionException e)
          {
              e.printStackTrace();
          }
      }
      
      public boolean doneContinue()
      {
          if (!enterSyscall)
              return true;
          performSyscall();
          return false;
      }
      
      public int getSyscallArg(int i) throws CPUException
      {
          return simulator.getArg(i+2);
      }
  
      public void writeUART(int val)
      {
          System.out.print((char)val);
          System.out.flush();
          
  
          Packet p=new Packet(this);
          p.reply("O" + formatHex(val, "00"));
          p.sendReply();
          
          
      }
      public int readUART() throws CPUException
      {
          try
          {
              if (System.in.available()<=0)
              {
                  throw new MemoryAccessException();
              }
              
              return System.in.read();
          } catch (IOException e)
          {
              e.printStackTrace();
          }
          return 0;
      }
  
      public int readFIFO()
      {
          try
          {
              return System.in.available()>0?0:1;
          } catch (IOException e)
          {
              e.printStackTrace();
          }
          return 1;
      }
  
  	public void halted()
  	{
  		// TODO Auto-generated method stub
  		
  	}
  
  	public void running()
  	{
  		// TODO Auto-generated method stub
  		
  	}
  }
  