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.11 christos 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.10 christos /* This must come before any other includes. */ 33 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.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.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