diff options
author | Jiri Gaisler <jiri@gaisler.se> | 2019-03-22 10:00:07 +0100 |
---|---|---|
committer | Jiri Gaisler <jiri@gaisler.se> | 2019-05-14 22:26:21 +0200 |
commit | 865b177d0e2fd534270ef158030e7c3056a930e3 (patch) | |
tree | 4edbf27496977adaed90287d11eaffbe357ac757 /remote.c |
Standalone sis - initial commit
Diffstat (limited to 'remote.c')
-rw-r--r-- | remote.c | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/remote.c b/remote.c new file mode 100644 index 0000000..f568673 --- /dev/null +++ b/remote.c @@ -0,0 +1,479 @@ +/* This file is part of SIS (SPARC/RISCV instruction simulator) + + Copyright (C) 2019 Free Software Foundation, Inc. + Contributed by Jiri Gaisler, European Space Agency + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* This code based on socket example at + * https://www.geeksforgeeks.org/socket-programming-cc/ + * and on sparc-stub.c from gdb. + */ + +#include <unistd.h> +#include <stdio.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <string.h> +#include <signal.h> +#include "sis.h" + +#define EBREAK 0x00100073 +#define CEBREAK 0x90002 +int new_socket; +static char sendbuf[2048] = "$"; +static const char hexchars[] = "0123456789abcdef"; +static int detach = 0; + +int +create_socket (int port) +{ + int server_fd; + struct sockaddr_in address; + int opt = 1; + int addrlen = sizeof (address); + struct protoent *proto; + + // Creating socket file descriptor + if ((server_fd = socket (AF_INET, SOCK_STREAM, 0)) == 0) + { + perror ("socket failed"); + return 0; + } + + // Forcefully attaching socket to the port + if (setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, + &opt, sizeof (opt))) + { + perror ("setsockopt"); + return 0; + } + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons (port); + + // Forcefully attaching socket to the port + if (bind (server_fd, (struct sockaddr *) &address, sizeof (address)) < 0) + { + perror ("bind failed"); + return 0; + } + if (listen (server_fd, 1) < 0) + { + perror ("listen"); + return 0; + } + if ((new_socket = accept (server_fd, (struct sockaddr *) &address, + (socklen_t *) & addrlen)) < 0) + { + perror ("accept"); + return 0; + } + close (server_fd); + setsockopt (new_socket, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof (opt)); + proto = getprotobyname ("tcp"); + setsockopt (new_socket, proto->p_proto, TCP_NODELAY, &opt, sizeof (opt)); + fcntl (new_socket, F_SETOWN, getpid ()); + fcntl (new_socket, F_SETFL, FASYNC); + + return 1; +} + +static int +hex (unsigned char ch) +{ + if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + if (ch >= '0' && ch <= '9') + return ch - '0'; + if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + return -1; +} + +void +checksum (char *buf) +{ + unsigned char sum = 0; + + while (*buf) + sum += *buf++; + *buf++ = '#'; + *buf++ = hexchars[sum >> 4]; + *buf++ = hexchars[sum & 0x0f]; + *buf++ = 0; +} + +int +check_pkg (unsigned char *buf, int len) +{ + int i, start = 0; + unsigned char chksum = 0; + unsigned char rxsum = 0; + + i = 0; + while ((i < len) && (buf[i] != '$')) + i++; + if (i == len) + return -1; + i++; + start = i; + while ((i < len) && (buf[i] != '#')) + { + chksum = chksum + buf[i++]; + } + if (i == len) + return -1; + i++; + rxsum = (hex (buf[i]) << 4) | hex (buf[i + 1]); + + if ((i < len) && (chksum == rxsum)) + return start; + return -1; +} + +static void +int2hex (unsigned char *hexbuf, unsigned char *intbuf, int len) +{ + int i; + for (i = 0; i < len; i++) + { + hexbuf[i * 2] = hexchars[intbuf[i] >> 4]; + hexbuf[i * 2 + 1] = hexchars[intbuf[i] & 0x0f]; + } + hexbuf[len * 2] = 0; +} + +static int +sim_stat () +{ + int i; + switch (simstat) + { + case NULL_HIT: + i = SIGSEGV; + break; + case ERROR: + i = SIGTERM; + break; + case CTRL_C: + i = SIGINT; + break; + default: + i = SIGTRAP; + } + return i; +} + +int +gdb_remote_exec (char *buf) +{ + unsigned char membuf[1024]; + unsigned int i, j, len, addr; + int cont = 1; + unsigned char *cptr, *mptr; + unsigned char *txbuf = &sendbuf[1]; + + switch (buf[0]) + { + case 'H': + if (buf[1] != 'c') + strcpy (txbuf, "OK"); + break; + case '?': /* last signal */ + if ((ebase.simtime == 0) && (sregs[cpu].pc == last_load_addr) && + last_load_addr) + sprintf (txbuf, "W%02d", sim_stat ()); + else + sprintf (txbuf, "S%02d", sim_stat ()); + break; + case 'D': /* detach */ + strcpy (txbuf, "OK"); + detach = 1; + break; + case 'g': /* get registers */ + len = arch->gdb_get_reg (membuf); + int2hex (txbuf, membuf, len); + break; + case 'm': /* read memory */ + i = 1; + len = 0; + addr = 0; + while (buf[i] && (buf[i] != ',')) + { + addr = (addr << 4) | hex (buf[i]); + i++; + } + i++; + while (buf[i] && (buf[i] != '#')) + { + len = (len << 4) | hex (buf[i]); + i++; + } + sim_read (addr, membuf, len); + int2hex (txbuf, membuf, len); + break; + case 'M': /* write memory */ + i = 1; + len = 0; + addr = 0; + while (buf[i] && (buf[i] != ',')) + { + addr = (addr << 4) | hex (buf[i]); + i++; + } + i++; + while (buf[i] && (buf[i] != ':')) + { + len = (len << 4) | hex (buf[i]); + i++; + } + i++; + j = 0; + while (buf[i] != '#') + { + membuf[j] = (hex (buf[i]) << 4) | hex (buf[i + 1]); + i += 2; + j += 1; + } + sim_write (addr, membuf, len); + strcpy (txbuf, "OK"); + break; + case 'P': /* write register */ + i = 1; + len = 0; + addr = 0; + while (buf[i] && (buf[i] != '=')) + { + addr = (addr << 4) | hex (buf[i]); + i++; + } + i++; + while (buf[i] && (buf[i] != '#')) + { + if (cputype == CPU_RISCV) + { + j = hex (buf[i++]); + j <<= 4; + j |= hex (buf[i]); + len = (j << 24) | (len >> 8); /* value is in target order! */ + } + else + len = (len << 4) | hex (buf[i]); + i++; + } + i++; + arch->set_register (&sregs[cpu], NULL, len, addr); + strcpy (txbuf, "OK"); + break; + case 'C': /* continue execution */ + sim_create_inferior (); + case 'c': + sim_resume (0); + i = sim_stat (); + sprintf (txbuf, "S%02x", i); + break; + case 'k': /* kill */ + case 'R': /* restart */ + sim_create_inferior (0, 0, 0, 0); + strcpy (txbuf, "OK"); + break; + case 'v': + if (strncmp (&buf[1], "Kill", 4) == 0) + { /* restart */ + sim_create_inferior (0, 0, 0, 0); + strcpy (txbuf, "OK"); + } + else if (strncmp (&buf[1], "Run;", 4) == 0) + { /* Restart */ + sim_create_inferior (0, 0, 0, 0); + strcpy (txbuf, "S00"); + } + else if (strncmp (&buf[1], "Cont", 4) == 0) + { /* continue/step */ + switch (buf[5]) + { + case '?': + strcpy (txbuf, "vCont;c;s"); + break; + case 'c': + sim_resume (0); + i = sim_stat (); + sprintf (txbuf, "S%02x", i); + break; + case 's': + sim_resume (1); + i = sim_stat (); + sprintf (txbuf, "S%02x", i); + break; + default: + strcpy (sendbuf, "$#"); + } + } + break; + case 's': + case 'S': + sim_resume (1); + i = sim_stat (); + sprintf (txbuf, "S%02x", i); + break; + case 'z': + case 'Z': + if (buf[1] == '0') + { /* insert sw break */ + i = 3; + addr = 0; + while (buf[i] && (buf[i] != ',')) + { + addr = (addr << 4) | hex (buf[i]); + i++; + } + i++; + len = hex (buf[i]); + if (buf[0] == 'Z') + j = sim_insert_swbreakpoint (addr, len); + else + j = sim_remove_swbreakpoint (addr, len); + if (j) + strcpy (txbuf, "OK"); + else + strcpy (txbuf, "E01"); + } + else + printf ("%s\n", buf); + break; + case 'q': /* query */ + if (strncmp (&buf[1], "fThreadInfo", 11) == 0) + { + strcpy (txbuf, "l"); + } + else if (strncmp (&buf[1], "Attached", 8) == 0) + { + strcpy (txbuf, "0"); + } + else if (strncmp (&buf[1], "sThreadInfo", 11) == 0) + { + strcpy (txbuf, "l"); + } + else if (strncmp (&buf[1], "Rcmd", 4) == 0) + { + cptr = &buf[6]; + mptr = membuf; + while (*cptr != '#') + *mptr++ = (hex (*cptr++) << 4) | hex (*cptr++); + *mptr = 0; + exec_cmd (membuf); + strcpy (txbuf, "OK"); + } + break; + case '!': /* extended protocl */ + strcpy (txbuf, "OK"); + break; + default: + printf ("%s\n", buf); + } + + checksum (txbuf); + return cont; +} + +void +gdb_remote (int port) +{ + char buffer[2048]; + int cont = 1; + int res, len = 0; + char ack = '+'; + char nok = '-'; + + sis_gdb_break = 1; + detach = 0; + signal (SIGIO, int_handler); + printf ("gdb: listening on port %d ", port); + while (cont) + { + if (cont = create_socket (port)) + { + send (new_socket, &ack, 1, 0); + printf ("connected\n"); + } + while (cont) + { + do + { + len = read (new_socket, buffer, 2048); + buffer[len] = 0; + if (sis_verbose) + printf ("%s (%d)\n", buffer, len); + if (len == 1) + if (buffer[0] == '-') + { + if (sis_verbose) + printf ("tx: %s\n", sendbuf); + send (new_socket, sendbuf, strlen (sendbuf), 0); + } + else if (buffer[0] == '+') + { + if (detach) + { + cont = 0; + break; + } + } + else if (buffer[0] == 3) + { + ctrl_c = 1; + } + if (len <= 0) + { + cont = 0; + break; + } + } + while (len < 2); + if (!cont) + break; + res = check_pkg (buffer, len); + if (res > 0) + { + if (sis_verbose) + printf ("tx: +\n"); + send (new_socket, &ack, 1, 0); + strcpy (sendbuf, "$"); + cont = gdb_remote_exec (&buffer[res]); + if (sis_verbose) + printf ("tx: %s\n", sendbuf); + send (new_socket, sendbuf, strlen (sendbuf), 0); + } + else + { + if (sis_verbose) + printf ("tx: -\n"); + send (new_socket, &nok, 1, 0); + } + } + } + if (new_socket) + { + close (new_socket); + } + new_socket = 0; + sis_gdb_break = 0; + signal (SIGIO, SIG_DFL); + +} |