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