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