xref: /netbsd-src/external/gpl3/gdb/dist/sim/cris/rvdummy.c (revision a8c74629f602faa0ccf8a463757d7baf858bbf3a)
1 /* Test-driver for the remote-virtual-component simulator framework
2    for GDB, the GNU Debugger.
3 
4    Copyright 2006-2020 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