/* * Motorola Background Debug Mode Remote Server * Copyright (C) 1994, 95, 96, 1997 Free Software Foundation, Inc. * Contributed by Chris Johns * * Pieces of code are taken from the gnatsd amd gdbserver. * * 31-11-1999 Chris Johns (ccj@acm.org) * * Chris Johns * Objective Design Systems * 35 Cairo Street * Cammeray, Sydney, 2062, Australia * * ccj@acm.org * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __CYGWIN32__ #include #endif char *xmalloc (unsigned n); void xfree (char *p); /* * This should be the same as the client. */ #define BDM_SERVER_TIMEOUT (5) #define BDM_SERVER_BUF_SIZE (4096) /* * Local data. */ static const char *version_string = "1.0.0"; static char myname[MAXHOSTNAMELEN]; static char *current_host; static char *current_addr; static char *program_name; static int debug = 0; /* * Define the messages between the client and the server. */ enum bdm_message_id { HELO, SRVCTL, IOINT, IOCMD, IOIO, READ, WRITE, QUIT, INVALID }; struct bdm_message { char *label; enum bdm_message_id id; }; struct bdm_message messages[] = { { "HELO", HELO }, { "SRVCTL", SRVCTL }, { "IOINT", IOINT }, { "IOCMD", IOCMD }, { "IOIO", IOIO}, { "READ", READ }, { "WRITE", WRITE }, { "QUIT", QUIT } }; /* * Ioctl code translation. */ static const int ioctl_code_table[] = { BDM_INIT, BDM_RESET_CHIP, BDM_RESTART_CHIP, BDM_STOP_CHIP, BDM_STEP_CHIP, BDM_GET_STATUS, BDM_SPEED, BDM_DEBUG, BDM_RELEASE_CHIP, BDM_GO, BDM_READ_REG, BDM_READ_SYSREG, BDM_READ_LONGWORD, BDM_READ_WORD, BDM_READ_BYTE, BDM_WRITE_REG, BDM_WRITE_SYSREG, BDM_WRITE_LONGWORD, BDM_WRITE_WORD, BDM_WRITE_BYTE, BDM_GET_DRV_VER, BDM_GET_CPU_TYPE, BDM_GET_IF_TYPE, BDM_GET_CF_PST, /* At the end to not break existing servers. */ BDM_SET_CF_PST, BDM_READ_CTLREG, BDM_WRITE_CTLREG, BDM_READ_DBREG, BDM_WRITE_DBREG }; /* * Get the name of the host. */ char * get_name (struct in_addr *host) { char *buf; int i; struct hostent *hp; #ifdef h_addr char **pp; #endif hp = gethostbyaddr ((char *) host, sizeof (host), AF_INET); if (hp == NULL) return NULL; i = strlen (hp->h_name); buf = (char *) xmalloc (i + 1); strcpy (buf, hp->h_name); hp = gethostbyname (buf); if (hp == NULL) return NULL; #ifdef h_addr for (pp = hp->h_addr_list; *pp; pp++) if (memcmp ((char *) &host->s_addr, (char *) *pp, hp->h_length) == 0) break; if (*pp == NULL) return NULL; #else if (memcmp ((char *) &host->s_addr, (char *) hp->h_addr, hp->h_length) != 0) return NULL; #endif return buf; } /* * Start an inetd connection. */ void start_connection () { struct sockaddr_in s; unsigned int len; len = sizeof (s); if (getpeername (0, (struct sockaddr *) &s, &len) < 0) { if (!isatty (0)) { syslog (LOG_ERR, "%s: can't get peername %m", "?"); exit (1); } current_host = "stdin"; current_addr = current_host; } else { if (s.sin_family != AF_INET) { syslog (LOG_ERR, "%s: bad address family %ld", "?", (long) s.sin_family); exit (1); } current_addr = (char *) inet_ntoa (s.sin_addr); current_host = get_name (&s.sin_addr); if (!current_host) { current_host = current_addr; } } } /* * Message the message from the input handle. */ int get_message (char *buf, int buf_len) { int numfds; fd_set readfds; while (1) { FD_ZERO (&readfds); FD_SET (0, &readfds); numfds = select (0 + 1, &readfds, 0, 0, 0); if (numfds > 0) { int ret = read (0, buf, buf_len-1); if (ret>=0) buf[ret]=0; return ret; } } } /* * Decode the id to an ioctl number. * * Note, watch checking the return value. Check for -1 not < 0. * * We should have version number checks between the client and server * to avoid these numbers skewing. */ int decode_id (unsigned long id) { if (id < (sizeof (ioctl_code_table) / sizeof (ioctl_code_table[0]))) return ioctl_code_table[id]; errno = EINVAL; return -1; } /* * Decode a message. */ enum bdm_message_id decode_message (char *message) { unsigned id; char *c; char *s; /* * Make the first field (the message label) uppercase. */ s = strchr (message, ' '); if (!s) s = message + strlen (message); for (c = message; c < s; c++) *c = toupper (*c); for (id = 0; id < (sizeof messages / sizeof (struct bdm_message)); id++) if (strncmp (message, messages[id].label, strlen (messages[id].label)) == 0) return messages[id].id; syslog (LOG_INFO, "invalid message: %s", message); return INVALID; } /* * Open the port using the requested device. */ void helo (char *device) { device += sizeof "HELO"; if (bdmOpen (device) < 0) { syslog (LOG_INFO, "open error: %s (%d), opening `%s'", bdmErrorString (), errno, device); } printf ("HELO %d %s BDM server %s ready.", errno, myname, version_string); } /* * Server Control. */ void server_control (char *message) { char *s = message + sizeof "SRVCTL"; if (strncmp (s, "DEBUG", sizeof "DEBUG" - 1) == 0) { s = strchr (s, '='); if (!s) { syslog (LOG_INFO, "srv-ctl error: invalid debug syntax (%s)", message); return; } s++; debug = strtoul (s, NULL, 0); syslog (LOG_INFO, "srv-ctl: debug level is %d", debug); } } /* * IO Int read/write. */ void ioint (char *message) { int id; int code; int var; message += sizeof "IOINT"; id = strtoul (message, NULL, 0); message = strchr (message, ',') + 1; var = strtoul (message, NULL, 0); code = decode_id (id); if (code == -1) { syslog (LOG_INFO, "ioint error: invalid ioctl id decode (%d)", errno); } if (bdmIoctlInt (code, &var) < 0) { syslog (LOG_INFO, "ioint error: %s (%d)", bdmErrorString (), errno); } printf ("IOINT %d,0x%x.", errno, var); } /* * IO Command. */ void iocmd (char *message) { int id; int code; message += sizeof "IOCMD"; id = strtoul (message, NULL, 0); code = decode_id (id); if (code == -1) { syslog (LOG_INFO, "iocmd error: invalid ioctl id decode (%d)", errno); } if (bdmIoctlCommand (code) < 0) { syslog (LOG_INFO, "iocmd error: %s (%d)", bdmErrorString (), errno); } printf ("IOCMD %d.", errno); } /* * IO ioctl addressed access. */ void ioio (char *message) { int id; int code; struct BDMioctl ioc; message += sizeof "IOIO"; id = strtoul (message, NULL, 0); message = strchr (message, ',') + 1; ioc.address = strtoul (message, NULL, 0); message = strchr (message, ',') + 1; ioc.value = strtoul (message, NULL, 0); code = decode_id (id); if (code == -1) { syslog (LOG_INFO, "ioio error: invalid ioctl id decode (%d)", errno); } if (bdmIoctlIo (code, &ioc) < 0) { syslog (LOG_INFO, "ioio error: %s (%d)", bdmErrorString (), errno); } printf ("IOIO %d,0x%x,0x%x.", errno, ioc.address, ioc.value); } /* * Read a block of memory. */ void bdm_read (char *message) { long read_nbytes; unsigned char *buf; unsigned long nbytes; unsigned long byte; message += sizeof "READ"; nbytes = strtoul (message, NULL, 0); buf = (unsigned char*) xmalloc ((unsigned) nbytes); read_nbytes = bdmRead (buf, nbytes); if (debug) syslog (LOG_INFO, "read: nbytes %ld (%ld), have read %ld", nbytes, nbytes * 2, read_nbytes); if (read_nbytes < 0) { syslog (LOG_INFO, "read error: %s (%d)", bdmErrorString (), errno); } printf ("READ %d,%ld,", errno, read_nbytes); if (read_nbytes > 0) { for (byte = 0; byte < read_nbytes; byte++) printf ("%02x", buf[byte]); } xfree ((char*) buf); } /* * Write a block of memory. */ void bdm_write (char *message, int msg_len, int msg_buf_len) { long written_nbytes; unsigned char *buf; unsigned long nbytes; unsigned long byte; unsigned long msg_bytes; int msg_index; unsigned char octet = 0; char *msg; nbytes = strtoul (message + sizeof "WRITE", &msg, 0); if (*msg == ',') msg++; buf = (unsigned char*) xmalloc ((unsigned) nbytes); byte = 0; msg_bytes = 0; msg_len -= msg - message; msg_buf_len -= msg - message; if (debug) syslog (LOG_INFO, "write: nbytes %ld (%ld)", nbytes, nbytes * 2); while (byte < nbytes) { msg_index = 0; if (msg_len < 2) { int new_read; new_read = get_message (msg + msg_len, msg_buf_len - msg_len); if (new_read < 0) { syslog (LOG_INFO, "write error: client timeout"); xfree ((char*) buf); return; } msg_len += new_read; } if ((msg_len > 0) && !msg[msg_len - 1]) msg_len--; if (debug) { syslog (LOG_INFO, "write read: msg len is %d (%ld/%ld)", msg_len, msg_bytes, msg_len + msg_bytes); syslog (LOG_INFO, "write read msg: %s", msg + msg_index); if (msg_len > 900) syslog (LOG_INFO, "write read msg end: %s", msg + msg_len - 100); } while ((byte < nbytes) && ((msg_len - msg_index) > 1)) { if ((msg[msg_index] >= '0') && (msg[msg_index] <= '9')) octet = msg[msg_index] - '0'; else if ((msg[msg_index] >= 'a') && (msg[msg_index] <= 'f')) { msg[msg_index] = tolower (msg[msg_index]); octet = msg[msg_index] - 'a' + 10; } else { syslog (LOG_INFO, "write read: hbyte %ld msg bytes %ld, len:%d index:%d," " invalid data %#2x", byte, msg_bytes, msg_len, msg_index, msg[msg_index]); } msg_index++; msg_bytes++; octet <<= 4; if ((msg[msg_index] >= '0') && (msg[msg_index] <= '9')) octet |= msg[msg_index] - '0'; else if ((msg[msg_index] >= 'a') && (msg[msg_index] <= 'f')) { msg[msg_index] = tolower (msg[msg_index]); octet |= msg[msg_index] - 'a' + 10; } else { syslog (LOG_INFO, "write read: lbyte %ld msg bytes %ld, len:%d index:%d," " invalid data %#2x", byte, msg_bytes, msg_len, msg_index, msg[msg_index]); } msg_index++; msg_bytes++; buf[byte] = octet; byte++; } memcpy (msg, msg + msg_index, msg_len - msg_index); msg_len -= msg_index; } written_nbytes = bdmWrite (buf, nbytes); if (written_nbytes < 0) { syslog (LOG_INFO, "write error: %s (%d)", bdmErrorString (), errno); } printf ("WRITE %d,%ld", errno, written_nbytes); xfree ((char*) buf); } /* * Clean up and exit. */ void quit () { bdmClose (); if (debug) syslog (LOG_INFO, "host finished: %s (%s)", current_host, current_addr); exit (0); } /* * Process a message. */ void process_message (char *message, int msg_len, int msg_buf_len) { errno = 0; switch (decode_message (message)) { case HELO: helo (message); break; case SRVCTL: server_control (message); break; case IOINT: ioint (message); break; case IOCMD: iocmd (message); break; case IOIO: ioio (message); break; case READ: bdm_read (message); break; case WRITE: bdm_write (message, msg_len, msg_buf_len); break; case QUIT: quit (); break; default: break; } } void usage () { fprintf (stderr, "Usage: %s [-h] [-n] [-V] [-d]\n", program_name); exit (1); } void version () { printf ("bdmd %s\n", version_string); } /* * The server can be run from inetd or run from the * a tty allow debug to be watched. * */ int main (int argc, char **argv) { struct hostent *hp; int optc; int not_inetd = 0; char buf[BDM_SERVER_BUF_SIZE]; int cread; program_name = argv[0]; while ((optc = getopt (argc, argv, "dnVh")) != EOF) { switch (optc) { case 'd': debug++; break; case 'n': not_inetd = 1; break; case 'V': version (); exit (0); break; case 'h': default: usage (); } } /* * Process options. */ umask (022); /* * chdir */ fflush (stderr); fflush (stdout); closelog (); #ifdef LOG_DAEMON openlog ("bdmd", (LOG_PID|LOG_CONS), LOG_DAEMON); #else openlog ("bdmd", LOG_PID); #endif if (gethostname (myname, MAXHOSTNAMELEN)) { fprintf (stderr, "%s: cannot find out the name of this host\n", program_name); exit (1); } myname[MAXHOSTNAMELEN - 1] = 0; /* * Now see if we can get a FQDN for this host. */ hp = gethostbyname (myname); if (hp && (strlen (hp->h_name) > strlen (myname))) strncpy (myname, hp->h_name, MAXHOSTNAMELEN); myname[MAXHOSTNAMELEN - 1] = 0; bdmLogSyslog (); /* * Don't pay attention to SIGPIPE; read will give us the problem * if it happens. */ signal (SIGPIPE, SIG_IGN); if (!not_inetd) start_connection (); else { current_host = myname; if (hp) current_addr = (char *) inet_ntoa (*(struct in_addr *) hp->h_addr); else current_addr = myname; } if (debug) syslog (LOG_INFO, "host connected: %s (%s)", current_host, current_addr); /* * Say hello to the remote end. It will be waiting. */ while (1) { cread = get_message (buf, BDM_SERVER_BUF_SIZE); if (cread == 0) { break; } if (cread > 0) { if (debug > 1) { int len = strlen (buf); syslog (LOG_INFO, "msg: %s", buf); if (len>900) syslog (LOG_INFO, "msg end: %s", buf + len - 100); } process_message (buf, cread, BDM_SERVER_BUF_SIZE); fflush (stdout); } } bdmClose (); return 0; }