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