/* Remote utility routines for the remote server for GDB. Copyright (C) 1986, 1989, 1993 Free Software Foundation, Inc. This file is part of GDB. 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "defs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include extern int remote_desc; extern int remote_debugging; void remote_open (); void remote_send (); void putpkt (); void getpkt (); void write_ok (); void write_enn (); void convert_ascii_to_int (); void convert_int_to_ascii (); void prepare_resume_reply (); /* Open a connection to a remote debugger. NAME is the filename used for communication. */ void remote_open (name, from_tty) char *name; int from_tty; { struct sgttyb sg; remote_debugging = 0; if (!strchr (name, ':')) { remote_desc = open (name, O_RDWR); if (remote_desc < 0) perror_with_name ("Could not open remote device"); ioctl (remote_desc, TIOCGETP, &sg); sg.sg_flags = RAW; ioctl (remote_desc, TIOCSETP, &sg); } else { char *port_str; int port; struct sockaddr_in sockaddr; int tmp; port_str = strchr (name, ':'); port = atoi (port_str + 1); remote_desc = socket (PF_INET, SOCK_STREAM, 0); if (remote_desc < 0) perror_with_name ("Can't open socket"); /* Allow rapid reuse of this port. */ tmp = 1; setsockopt (remote_desc, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, sizeof(tmp)); /* Enable TCP keep alive process. */ tmp = 1; setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp)); sockaddr.sin_family = PF_INET; sockaddr.sin_port = htons(port); sockaddr.sin_addr.s_addr = INADDR_ANY; if (bind (remote_desc, &sockaddr, sizeof (sockaddr)) || listen (remote_desc, 1)) perror_with_name ("Can't bind address"); tmp = sizeof (sockaddr); remote_desc = accept (remote_desc, &sockaddr, &tmp); if (remote_desc == -1) perror_with_name ("Accept failed"); tmp = 1; setsockopt (remote_desc, 6, TCP_NODELAY, (char *)&tmp, sizeof(tmp)); } fprintf (stderr, "Remote debugging using %s\n", name); remote_debugging = 1; } /* Convert hex digit A to a number. */ static int fromhex (a) int a; { if (a >= '0' && a <= '9') return a - '0'; else if (a >= 'a' && a <= 'f') return a - 'a' + 10; else error ("Reply contains invalid hex digit"); } /* Convert number NIB to a hex digit. */ static int tohex (nib) int nib; { if (nib < 10) return '0' + nib; else return 'a' + nib - 10; } /* Send the command in BUF to the remote machine, and read the reply into BUF. Report an error if we get an error reply. */ void remote_send (buf) char *buf; { putpkt (buf); getpkt (buf); if (buf[0] == 'E') error ("Remote failure reply: E"); } /* Send a packet to the remote machine, with error checking. The data of the packet is in BUF. */ void putpkt (buf) char *buf; { int i; unsigned char csum = 0; char buf2[2000]; char buf3[1]; int cnt = strlen (buf); char *p; /* Copy the packet into buffer BUF2, encapsulating it and giving it a checksum. */ p = buf2; *p++ = '$'; for (i = 0; i < cnt; i++) { csum += buf[i]; *p++ = buf[i]; } *p++ = '#'; *p++ = tohex ((csum >> 4) & 0xf); *p++ = tohex (csum & 0xf); /* Send it over and over until we get a positive ack. */ do { write (remote_desc, buf2, p - buf2); read (remote_desc, buf3, 1); } while (buf3[0] != '+'); } static int readchar () { static char buf[BUFSIZ]; static int bufcnt = 0; static char *bufp; if (bufcnt-- > 0) return *bufp++ & 0x7f; bufcnt = read (remote_desc, buf, sizeof (buf)); if (bufcnt <= 0) { perror ("readchar"); fatal ("read error, quitting"); } bufp = buf; bufcnt--; return *bufp++ & 0x7f; } /* Read a packet from the remote machine, with error checking, and store it in BUF. */ void getpkt (buf) char *buf; { char *bp; unsigned char csum, c1, c2; int c; while (1) { csum = 0; while ((c = readchar ()) != '$'); bp = buf; while (1) { c = readchar (); if (c == '#') break; *bp++ = c; csum += c; } *bp = 0; c1 = fromhex (readchar ()); c2 = fromhex (readchar ()); if (csum == (c1 << 4) + c2) break; fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", (c1 << 4) + c2, csum, buf); write (remote_desc, "-", 1); } write (remote_desc, "+", 1); } void write_ok (buf) char *buf; { buf[0] = 'O'; buf[1] = 'k'; buf[2] = '\0'; } void write_enn (buf) char *buf; { buf[0] = 'E'; buf[1] = 'N'; buf[2] = 'N'; buf[3] = '\0'; } void convert_int_to_ascii (from, to, n) char *from, *to; int n; { int nib; char ch; while (n--) { ch = *from++; nib = ((ch & 0xf0) >> 4) & 0x0f; *to++ = tohex (nib); nib = ch & 0x0f; *to++ = tohex (nib); } *to++ = 0; } void convert_ascii_to_int (from, to, n) char *from, *to; int n; { int nib1, nib2; while (n--) { nib1 = fromhex (*from++); nib2 = fromhex (*from++); *to++ = (((nib1 & 0x0f) << 4) & 0xf0) | (nib2 & 0x0f); } } static char * outreg(regno, buf) int regno; char *buf; { extern char registers[]; *buf++ = tohex (regno >> 4); *buf++ = tohex (regno & 0xf); *buf++ = ':'; convert_int_to_ascii (®isters[REGISTER_BYTE (regno)], buf, 4); buf += 8; *buf++ = ';'; return buf; } void prepare_resume_reply (buf, status, signal) char *buf, status; unsigned char signal; { int nib; char ch; *buf++ = 'T'; nib = ((signal & 0xf0) >> 4); *buf++ = tohex (nib); nib = signal & 0x0f; *buf++ = tohex (nib); buf = outreg (PC_REGNUM, buf); buf = outreg (FP_REGNUM, buf); buf = outreg (SP_REGNUM, buf); #ifdef NPC_REGNUM buf = outreg (NPC_REGNUM, buf); #endif #ifdef O7_REGNUM buf = outreg (O7_REGNUM, buf); #endif *buf++ = 0; } void decode_m_packet (from, mem_addr_ptr, len_ptr) char *from; unsigned int *mem_addr_ptr, *len_ptr; { int i = 0, j = 0; char ch; *mem_addr_ptr = *len_ptr = 0; while ((ch = from[i++]) != ',') { *mem_addr_ptr = *mem_addr_ptr << 4; *mem_addr_ptr |= fromhex (ch) & 0x0f; } for (j = 0; j < 4; j++) { if ((ch = from[i++]) == 0) break; *len_ptr = *len_ptr << 4; *len_ptr |= fromhex (ch) & 0x0f; } } void decode_M_packet (from, mem_addr_ptr, len_ptr, to) char *from, *to; unsigned int *mem_addr_ptr, *len_ptr; { int i = 0, j = 0; char ch; *mem_addr_ptr = *len_ptr = 0; while ((ch = from[i++]) != ',') { *mem_addr_ptr = *mem_addr_ptr << 4; *mem_addr_ptr |= fromhex (ch) & 0x0f; } while ((ch = from[i++]) != ':') { *len_ptr = *len_ptr << 4; *len_ptr |= fromhex (ch) & 0x0f; } convert_ascii_to_int (&from[i++], to, *len_ptr); }