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