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