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