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