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