Home | History | Annotate | Line # | Download | only in cris
rvdummy.c revision 1.9.2.1
      1 /* Test-driver for the remote-virtual-component simulator framework
      2    for GDB, the GNU Debugger.
      3 
      4    Copyright 2006-2023 Free Software Foundation, Inc.
      5 
      6    This file is part of GDB.
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     20 
     21 /* Avoid any problems whatsoever building this program if we're not
     22    also building hardware support.  */
     23 
     24 #if !WITH_HW
     25 int
     26 main (int argc, char *argv[])
     27 {
     28   return 2;
     29 }
     30 #else
     31 
     32 /* This must come before any other includes.  */
     33 #include "defs.h"
     34 
     35 #include "getopt.h"
     36 #include "libiberty.h"
     37 
     38 #include <stdio.h>
     39 
     40 #ifdef HAVE_UNISTD_H
     41 #include <unistd.h>
     42 #endif
     43 #include <stdlib.h>
     44 #include <string.h>
     45 #ifdef HAVE_SYS_TYPES_H
     46 #include <sys/types.h>
     47 #endif
     48 
     49 #include <sys/time.h>
     50 
     51 #include <errno.h>
     52 
     53 /* Not guarded in dv-sockser.c, so why here.  */
     54 #include <netinet/in.h>
     55 #include <arpa/inet.h>
     56 #include <netdb.h>
     57 #include <sys/select.h>
     58 #include <sys/socket.h>
     59 
     60 enum rv_command {
     61   RV_READ_CMD = 0,
     62   RV_WRITE_CMD = 1,
     63   RV_IRQ_CMD = 2,
     64   RV_MEM_RD_CMD = 3,
     65   RV_MEM_WR_CMD = 4,
     66   RV_MBOX_HANDLE_CMD = 5,
     67   RV_MBOX_PUT_CMD = 6,
     68   RV_WATCHDOG_CMD = 7
     69 };
     70 
     71 enum opts { OPT_PORT = 1, OPT_TIMEOUT, OPT_VERBOSE };
     72 
     73 struct option longopts[] =
     74   {
     75     {"port", required_argument, NULL, OPT_PORT},
     76     {"timeout", required_argument, NULL, OPT_TIMEOUT},
     77     {"verbose", no_argument, NULL, OPT_VERBOSE},
     78     {NULL, 0, NULL, 0}
     79   };
     80 
     81 int port = 10000;
     82 time_t timeout = 30000;
     83 char *progname = "(unknown)";
     84 int verbose = 0;
     85 
     86 /* Required forward-declarations.  */
     87 static void handle_input_file (int, char *);
     88 
     89 /* Set up a "server" listening to the port in PORT for a raw TCP
     90    connection.  Return a file descriptor for the connection or -1 on
     91    error.  */
     92 
     93 static int setupsocket (void)
     94 {
     95   int s;
     96   socklen_t len;
     97   int reuse = 1;
     98   struct sockaddr_in sa_in;
     99   struct sockaddr_in from;
    100 
    101   len = sizeof (from);
    102   memset (&from, 0, len);
    103   memset (&sa_in, 0, sizeof (sa_in));
    104 
    105   s = socket (AF_INET, SOCK_STREAM, 0);
    106   if (s == -1)
    107     return -1;
    108 
    109   if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse) != 0)
    110     return -1;
    111 
    112   sa_in.sin_port = htons (port);
    113   sa_in.sin_family = AF_INET;
    114 
    115   if (bind (s, (struct sockaddr *) & sa_in, sizeof sa_in) < 0)
    116     return -1;
    117 
    118   if (listen (s, 1) < 0)
    119     return -1;
    120 
    121   return accept (s, (struct sockaddr *) &from, &len);
    122 }
    123 
    124 /* Basic host-to-little-endian 32-bit value.  Could use the BFD
    125    machinery, but let's avoid it for this only dependency.  */
    126 
    127 static void
    128 h2le32 (unsigned char *dest, unsigned int val)
    129 {
    130   dest[0] = val & 255;
    131   dest[1] = (val >> 8) & 255;
    132   dest[2] = (val >> 16) & 255;
    133   dest[3] = (val >> 24) & 255;
    134 }
    135 
    136 /* Send a blob of data.  */
    137 
    138 static void
    139 send_output (int fd, unsigned char *buf, int nbytes)
    140 {
    141   while (nbytes > 0)
    142     {
    143       ssize_t written = write (fd, buf, nbytes);
    144       if (written < 0)
    145 	{
    146 	  fprintf (stderr, "%s: write to socket failed: %s\n",
    147 		  progname, strerror (errno));
    148 	  exit (2);
    149 	}
    150       nbytes -= written;
    151     }
    152 }
    153 
    154 /* Receive a blob of data, NBYTES large.  Compare to the first NCOMP
    155    bytes of BUF; if not a match, write error message to stderr and
    156    exit (2).  Else put it in buf.  */
    157 
    158 static void
    159 expect_input (int fd, unsigned char *buf, int nbytes, int ncomp)
    160 {
    161   unsigned char byt;
    162   int i;
    163 
    164   for (i = 0; i < nbytes; i++)
    165     {
    166       int r;
    167 
    168       do
    169 	{
    170 	  errno = 0;
    171 	  r = read (fd, &byt, 1);
    172 	}
    173       while (r <= 0 && (r == 0 || errno == EAGAIN));
    174 
    175       if (r != 1)
    176 	{
    177 	  fprintf (stderr, "%s: read from socket failed: %s",
    178 		  progname, strerror (errno));
    179 	  exit (2);
    180 	}
    181 
    182       if (i < ncomp && byt != buf[i])
    183 	{
    184 	  int j;
    185 	  fprintf (stderr, "%s: unexpected input,\n ", progname);
    186 	  if (i == 0)
    187 	    fprintf (stderr, "nothing,");
    188 	  else
    189 	    for (j = 0; j < i; j++)
    190 	      fprintf (stderr, "%02x", buf[j]);
    191 	  fprintf (stderr, "\nthen %02x instead of %02x\n", byt, buf[i]);
    192 	  exit (2);
    193 	}
    194       else
    195 	buf[i] = byt;
    196     }
    197 }
    198 
    199 /* Handle everything about a nil-terminated line of input.
    200    Call exit (2) on error with error text on stderr.  */
    201 
    202 static void
    203 handle_input (int fd, char *buf, char *fname, int lineno)
    204 {
    205   int nbytes = 0;
    206   int n = -1;
    207   char *s = buf + 2;
    208   unsigned int data;
    209   static unsigned char bytes[1024];
    210   int i;
    211 
    212   memset (bytes, 0, sizeof bytes);
    213   lineno++;
    214 
    215   if (buf[1] != ',')
    216     goto syntax_error;
    217 
    218   switch (buf[0])
    219     {
    220       /* Comment characters and empty lines.  */
    221     case 0: case '!': case '#':
    222       break;
    223 
    224       /* Include another file.  */
    225     case '@':
    226       handle_input_file (fd, s);
    227       break;
    228 
    229       /* Raw input (to be expected).  */
    230     case 'i':
    231       do
    232 	{
    233 	  n = -1;
    234 	  sscanf (s, "%02x%n", &data, &n);
    235 	  s += n;
    236 	  if (n > 0)
    237 	    bytes[nbytes++] = data;
    238 	}
    239       while (n > 0);
    240       expect_input (fd, bytes, nbytes, nbytes);
    241       if (verbose)
    242 	{
    243 	  printf ("i,");
    244 	  for (i = 0; i < nbytes; i++)
    245 	    printf ("%02x", bytes[i]);
    246 	  printf ("\n");
    247 	}
    248       break;
    249 
    250       /* Raw output (to be written).  */
    251     case 'o':
    252       do
    253 	{
    254 	  n = -1;
    255 	  sscanf (s, "%02x%n", &data, &n);
    256 	  if (n > 0)
    257 	    {
    258 	      s += n;
    259 	      bytes[nbytes++] = data;
    260 	    }
    261 	}
    262       while (n > 0);
    263       if (*s != 0)
    264 	goto syntax_error;
    265       send_output (fd, bytes, nbytes);
    266       if (verbose)
    267 	{
    268 	  printf ("o,");
    269 	  for (i = 0; i < nbytes; i++)
    270 	    printf ("%02x", bytes[i]);
    271 	  printf ("\n");
    272 	}
    273       break;
    274 
    275       /* Read a register.  */
    276     case 'r':
    277       {
    278 	unsigned int addr;
    279 	sscanf (s, "%x,%x%n", &addr, &data, &n);
    280 	if (n < 0 || s[n] != 0)
    281 	  goto syntax_error;
    282 	bytes[0] = 11;
    283 	bytes[1] = 0;
    284 	bytes[2] = RV_READ_CMD;
    285 	h2le32 (bytes + 3, addr);
    286 	expect_input (fd, bytes, 11, 7);
    287 	h2le32 (bytes + 7, data);
    288 	send_output (fd, bytes, 11);
    289 	if (verbose)
    290 	  printf ("r,%x,%x\n", addr, data);
    291       }
    292       break;
    293 
    294       /* Write a register.  */
    295     case 'w':
    296       {
    297 	unsigned int addr;
    298 	sscanf (s, "%x,%x%n", &addr, &data, &n);
    299 	if (n < 0 || s[n] != 0)
    300 	  goto syntax_error;
    301 	bytes[0] = 11;
    302 	bytes[1] = 0;
    303 	bytes[2] = RV_WRITE_CMD;
    304 	h2le32 (bytes + 3, addr);
    305 	h2le32 (bytes + 7, data);
    306 	expect_input (fd, bytes, 11, 11);
    307 	send_output (fd, bytes, 11);
    308 	if (verbose)
    309 	  printf ("w,%x,%x\n", addr, data);
    310       }
    311       break;
    312 
    313       /* Wait for some milliseconds.  */
    314     case 't':
    315       {
    316 	int del = 0;
    317 	struct timeval to;
    318 	sscanf (s, "%d%n", &del, &n);
    319 	if (n < 0 || s[n] != 0 || del == 0)
    320 	  goto syntax_error;
    321 
    322 	to.tv_sec = del / 1000;
    323 	to.tv_usec = (del % 1000) * 1000;
    324 
    325 	if (select (0, NULL, NULL, NULL, &to) != 0)
    326 	  {
    327 	    fprintf (stderr, "%s: problem waiting for %d ms:\n %s\n",
    328 		     progname, del, strerror (errno));
    329 	    exit (2);
    330 	  }
    331 	if (verbose)
    332 	  printf ("t,%d\n", del);
    333       }
    334       break;
    335 
    336       /* Expect a watchdog command.  */
    337     case 'W':
    338       if (*s != 0)
    339 	goto syntax_error;
    340       bytes[0] = 3;
    341       bytes[1] = 0;
    342       bytes[2] = RV_WATCHDOG_CMD;
    343       expect_input (fd, bytes, 3, 3);
    344       if (verbose)
    345 	printf ("W\n");
    346       break;
    347 
    348       /* Send an IRQ notification.  */
    349     case 'I':
    350       sscanf (s, "%x%n", &data, &n);
    351       if (n < 0 || s[n] != 0)
    352 	goto syntax_error;
    353       bytes[0] = 7;
    354       bytes[1] = 0;
    355       bytes[2] = RV_IRQ_CMD;
    356       h2le32 (bytes + 3, data);
    357       send_output (fd, bytes, 7);
    358       if (verbose)
    359 	printf ("I,%x\n", data);
    360       break;
    361 
    362       /* DMA store (to CPU).  */
    363     case 's':
    364       {
    365 	unsigned int addr;
    366 	sscanf (s, "%x,%n", &addr, &n);
    367 
    368 	if (n < 0 || s[n] == 0)
    369 	  goto syntax_error;
    370 	s += n;
    371 	do
    372 	  {
    373 	    n = -1;
    374 	    sscanf (s, "%02x%n", &data, &n);
    375 	    if (n > 0)
    376 	      {
    377 		s += n;
    378 		bytes[11 + nbytes++] = data;
    379 	      }
    380 	  }
    381 	while (n > 0);
    382 
    383 	if (*s != 0)
    384 	  goto syntax_error;
    385 	h2le32 (bytes, nbytes + 11);
    386 	bytes[2] = RV_MEM_WR_CMD;
    387 	h2le32 (bytes + 3, addr);
    388 	h2le32 (bytes + 7, nbytes);
    389 	send_output (fd, bytes, nbytes + 11);
    390 	if (verbose)
    391 	  {
    392 	    printf ("s,%x,", addr);
    393 	    for (i = 0; i < nbytes; i++)
    394 	      printf ("%02x", bytes[i]);
    395 	    printf ("\n");
    396 	  }
    397       }
    398       break;
    399 
    400       /* DMA load (from CPU).  */
    401     case 'l':
    402       {
    403 	unsigned int addr;
    404 	sscanf (s, "%x,%n", &addr, &n);
    405 
    406 	if (n < 0 || s[n] == 0)
    407 	  goto syntax_error;
    408 	s += n;
    409 	do
    410 	  {
    411 	    n = -1;
    412 	    sscanf (s, "%02x%n", &data, &n);
    413 	    if (n > 0)
    414 	      {
    415 		s += n;
    416 		bytes[11 + nbytes++] = data;
    417 	      }
    418 	  }
    419 	while (n > 0);
    420 
    421 	if (*s != 0)
    422 	  goto syntax_error;
    423 	h2le32 (bytes, nbytes + 11);
    424 	bytes[0] = 11;
    425 	bytes[1] = 0;
    426 	bytes[2] = RV_MEM_RD_CMD;
    427 	h2le32 (bytes + 3, addr);
    428 	h2le32 (bytes + 7, nbytes);
    429 	send_output (fd, bytes, 11);
    430 	bytes[0] = (nbytes + 11) & 255;
    431 	bytes[1] = ((nbytes + 11) >> 8) & 255;
    432 	expect_input (fd, bytes, nbytes + 11, nbytes + 11);
    433 	if (verbose)
    434 	  {
    435 	    printf ("l,%x,", addr);
    436 	    for (i = 0; i < nbytes; i++)
    437 	      printf ("%02x", bytes[i]);
    438 	    printf ("\n");
    439 	  }
    440       }
    441       break;
    442 
    443     syntax_error:
    444     default:
    445       fprintf (stderr, "%s: invalid command line in %s:%d:\n %s",
    446 	       progname, fname, lineno, strerror (errno));
    447       exit (2);
    448     }
    449 }
    450 
    451 /* Loop over the contents of FNAME, using handle_input to parse each line.
    452    Errors to stderr, exit (2).  */
    453 
    454 static void
    455 handle_input_file (int fd, char *fname)
    456 {
    457   static char buf[2048] = {0};
    458   int lineno = 0;
    459   FILE *f = fopen (fname, "r");
    460 
    461   if (f == NULL)
    462     {
    463       fprintf (stderr, "%s: problem opening %s: %s\n",
    464 	       progname, fname, strerror (errno));
    465       exit (2);
    466     }
    467 
    468   /* Let's cut the buffer short, so we always get a newline.  */
    469   while (fgets (buf, sizeof (buf) - 1, f) != NULL)
    470     {
    471       buf[strlen (buf) - 1] = 0;
    472       lineno++;
    473       handle_input (fd, buf, fname, lineno);
    474     }
    475 
    476   fclose (f);
    477 }
    478 
    479 int
    480 main (int argc, char *argv[])
    481 {
    482   int optc;
    483   int fd;
    484   FILE *f;
    485   int i;
    486 
    487   progname = argv[0];
    488   while ((optc = getopt_long (argc, argv, "", longopts, NULL)) != -1)
    489     switch (optc)
    490       {
    491       case OPT_PORT:
    492 	port = atoi (optarg);
    493 	break;
    494 
    495       case OPT_TIMEOUT:
    496 	timeout = (time_t) atoi (optarg);
    497 	break;
    498 
    499       case OPT_VERBOSE:
    500 	verbose = 1;
    501 	break;
    502       }
    503 
    504   fd = setupsocket ();
    505   if (fd == -1)
    506     {
    507       fprintf (stderr, "%s: problem setting up the connection: %s\n",
    508 	       progname, strerror (errno));
    509       exit (2);
    510     }
    511 
    512   for (i = optind; i < argc; i++)
    513     handle_input_file (fd, argv[i]);
    514 
    515   /* FIXME: option-controlled test for remaining input?  */
    516   close (fd);
    517   return 1;
    518 }
    519 #endif
    520