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