Beispiel #1
0
void attach_to_cpu ( void )
{
  // Stall the CPU before doing anything else. Otherwise, there would be a window of opportunity
  // for the software to modify the same SPR registers being accessed here.
  stall_cpu();

  uint32_t val;
  dbg_cpu0_read_spr_e( OR1200_DU_WATCHPOINT_COUNT, &val );
  rsp.watchpoint_count = val;

  dbg_cpu0_read_spr_e( SPR_VR , &rsp.spr_vr  );
  dbg_cpu0_read_spr_e( SPR_UPR, &rsp.spr_upr );

  for ( unsigned i = 0; i < MAX_WATCHPOINT_COUNT; ++i )
    rsp.watchpoint_addr[ i ] = 0;

  printf( "Attached to CPU, SPR VR (version): 0x%08X, SPR UPR (unit presence): 0x%08X\n",
          rsp.spr_vr, rsp.spr_upr );

  // Set up the CPU to break to the Debug Unit on exceptions.
  // Note that the current OR10 implementation only supports breaking on the l.trap instruction (TRAP exception).
  dbg_cpu0_write_spr_e( SPR_DSR, SPR_DSR_TE );

  // Just in case the single-step mode was activated, reset it.
  set_single_step_mode( false );

  collect_cpu_stop_reason( true );

  // Leave the CPU stalled. This is what GDB expects upon connecting.

  rsp.cpu_poll_speed = CPS_SLOW;
}
Beispiel #2
0
void process_client_command ( const rsp_buf * const buf )
{
  if ( rsp.is_target_running )
  {
    // printf( "BREAK received while CPU running.\n" );
    if ( buf->data[0] == GDB_RSP_BREAK_CMD )
    {
      stall_cpu();
      collect_cpu_stop_reason( true );
      send_signal_reply_packet();
      rsp.cpu_poll_speed = CPS_SLOW;
      return;
    }

    throw std::runtime_error( "A GDB RSP command was received while the CPU was running, which is an indication "
                              "that the RSP handling got out of sync." );
  }

  assert( rsp.cpu_poll_speed == CPS_SLOW );

  switch ( buf->data[0] )
  {
  case GDB_RSP_BREAK_CMD:
    // The target was not running and a break command was received. This can happen if the user
    // issues a break (with Ctrl+C) but the CPU just stalled for anothe reason.
    send_signal_reply_packet();
    break;

  case '!':
    // Request for extended remote mode, which we do support.
    send_ok_packet( rsp.client_fd );
    break;

  case '?':
    send_signal_reply_packet();
    break;

  case 'c':
    rsp_continue( buf );
    break;

  case 'g':
    rsp_read_all_regs();
    break;

  case 'H':
    // Set the thread number of any subsequent operations.
    // Hc is for step and continue operations, Hg for all other operations.
    // The thread number can be -1 for all threads, a thread number, or 0 for "just pick any thread".
    // We only support one thread, so ignore all arguments and just reply "OK"
    send_ok_packet( rsp.client_fd );
    break;

  case 'k':
    kill_request();
    break;

  case 'm':
    rsp_read_mem( buf );
    break;

  case 'M':
    rsp_write_mem( buf );
    break;

  case 'P':
    rsp_write_reg( buf );
    break;

  case 'q':
    // General query packets.
    rsp_query( buf );
    break;

  case 's':
    // Single step (one high level instruction). This could be hard without DWARF2 info.
    rsp_step( buf );
    break;

  case 'v':
    // Any one of a number of packets to control execution
    rsp_vpkt( buf );
    break;


  // ----- These are all packets that we have decided not to support -----

  case 'z':
  case 'Z':
    rsp_watchpoint( buf );
    break;

  case 'D':  // Detach GDB. I'm not sure what to do in this case. If you type "detach" in the current
             // GDB version it does not close the connection and it triggers error message
             // "A problem internal to GDB has been detected".

  case 'X':  // We don't support binary memory writes. The old code did, so it should not be hard
             // to port it to this new implementation. This is only an optimisation, as GDB
             // will fall back to using text-based memory writes (see the 'M' command).
    send_unknown_command_reply( rsp.client_fd );
    break;

  default:
    // Assert on all unsupported packets that were not already known to the developer. This helps catch bugs.
    #ifndef NDEBUG
      printf( "Unknown RSP packet received: %s\n", format_packet_for_tracing_purposes( buf ).c_str() );
      assert( false );
    #endif

    send_unknown_command_reply( rsp.client_fd );
    break;
  }
}
void *target_handler(void *arg)
{
  struct timeval tv;
  fd_set  readset;
  int i, fd, ret, nfds;
  char cmd;
  unsigned char target_status;

  debug("Target handler thread started!\n");

  while(1)
    {
      // Set this each loop, it may be changed by the select() call
      tv.tv_sec = 0;
      tv.tv_usec = 250000;  // 1/4 second timeout when polling

      FD_ZERO(&readset);
      nfds = 0;

      pthread_mutex_lock(&pipes_mutex);
      for(i = 0; i < num_monitor_connections; i++)
	{
	  fd = connections[i].server_to_monitor_fds[0];
	  FD_SET(fd, &readset);
	  if(fd > nfds)
	    nfds = fd;
	}
      pthread_mutex_unlock(&pipes_mutex);
      nfds++;

      // We do not hold the pipes_mutex during the select(), so it is possible that some of
      // the pipes in the readset will go away while we block.  This is fine, as we re-take
      // the lock below and iterate through the (changed) connections[] array, which will
      // ignore any pipes which have closed, even if they are in the readset.

      ret = select(nfds, &readset, NULL, NULL, &tv);

      if(ret == -1)  // error
	{
	  // We may get an EBADF if a server un-registers its pipes while we're in the select() 
	  // (very likely).  So, ignore EBADF unless there's a problem that needs debugged.
	  if(errno != EBADF)
	    perror("select()");
	  else
	    {
	      debug("Monitor thread got EBADF in select().  Server unregistration, or real problem?");
	    }
	}
      else if(ret != 0)  // fd ready (ret == 0 on timeout)
	{
	  debug("Monitor thread got data\n");
	  pthread_mutex_lock(&pipes_mutex);
	  for(i = 0; i < num_monitor_connections; i++)
	    {
	      debug("Monitor checking incoming connection %i\n", i);
	      fd = connections[i].server_to_monitor_fds[0];
	      if(FD_ISSET(fd, &readset))
		{
		  ret = read(fd, &cmd, 1);
		  debug("Target monitor thread got command \'%c\' (0x%X)\n", cmd, cmd);
		  if(ret == 1)
		    {
		      if(cmd == 'S')  
			{
			  if(target_is_running)  stall_cpu(1); 
			  notify_listeners("H", 1);
			}
		      else if(cmd == 'U')  
			{
			  if(!target_is_running) stall_cpu(0);
			  notify_listeners("R", 1);
			}
		      else
			{
			  fprintf(stderr, "Target monitor thread got unknown command \'%c\' (0x%X)\n", cmd, cmd);
			}
		    }
		  else
		    {
		      fprintf(stderr, "Monitor thread failed to read from ready descriptor!\n");
		    }
		}  // if FD_ISSET()
	    }  // for i = 0 to num_monitor_connections
	  pthread_mutex_unlock(&pipes_mutex);

	  // We got a command.  Either the target is now stalled and we don't need to poll,
	  // or the target just started and we should wait a bit before polling.
	  continue;

	}  // else if (ret != 0)


      if(target_is_running)
	{
	  debug("Monitor polling hardware!\n");
	  // Poll target hardware
	  ret = dbg_cpu0_read_ctrl(0, &target_status);
	  if(ret != APP_ERR_NONE)
	    fprintf(stderr, "ERROR 0x%X while polling target CPU status\n", ret);
	  else {
	    if(target_status & 0x01)  // Did we get the stall bit?  Bit 0 is STALL bit.
	      {
		debug("Monitor poll found CPU stalled!\n");
		target_is_running = 0;
		pthread_mutex_lock(&pipes_mutex);
		notify_listeners("H", 1);
		pthread_mutex_unlock(&pipes_mutex);
	      }
	  }
	}  // if(target_is_running)


    }  // while(1), main loop

  fprintf(stderr, "Target monitor thread exiting!!");

  return arg;
}