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