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